aboutsummaryrefslogtreecommitdiffhomepage
path: root/assets/php/vendor/react/event-loop/src
diff options
context:
space:
mode:
authormarvin-borner@live.com2018-04-10 21:50:16 +0200
committermarvin-borner@live.com2018-04-10 21:54:48 +0200
commitfc9401f04a3aca5abb22f87ebc210de8afe11d32 (patch)
treeb0b310f3581764ec3955f4e496a05137a32951c3 /assets/php/vendor/react/event-loop/src
parent286d643180672f20526f3dc3bd19d7b751e2fa97 (diff)
Initial Commit
Diffstat (limited to 'assets/php/vendor/react/event-loop/src')
-rw-r--r--assets/php/vendor/react/event-loop/src/ExtEvLoop.php252
-rw-r--r--assets/php/vendor/react/event-loop/src/ExtEventLoop.php259
-rw-r--r--assets/php/vendor/react/event-loop/src/ExtLibevLoop.php199
-rw-r--r--assets/php/vendor/react/event-loop/src/ExtLibeventLoop.php283
-rw-r--r--assets/php/vendor/react/event-loop/src/Factory.php41
-rw-r--r--assets/php/vendor/react/event-loop/src/LoopInterface.php463
-rw-r--r--assets/php/vendor/react/event-loop/src/SignalsHandler.php63
-rw-r--r--assets/php/vendor/react/event-loop/src/StreamSelectLoop.php275
-rw-r--r--assets/php/vendor/react/event-loop/src/Tick/FutureTickQueue.php60
-rw-r--r--assets/php/vendor/react/event-loop/src/Timer/Timer.php55
-rw-r--r--assets/php/vendor/react/event-loop/src/Timer/Timers.php109
-rw-r--r--assets/php/vendor/react/event-loop/src/TimerInterface.php27
12 files changed, 2086 insertions, 0 deletions
diff --git a/assets/php/vendor/react/event-loop/src/ExtEvLoop.php b/assets/php/vendor/react/event-loop/src/ExtEvLoop.php
new file mode 100644
index 0000000..74db6d0
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/ExtEvLoop.php
@@ -0,0 +1,252 @@
+<?php
+
+namespace React\EventLoop;
+
+use Ev;
+use EvIo;
+use EvLoop;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-ev` based event loop.
+ *
+ * This loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev),
+ * that provides an interface to `libev` library.
+ *
+ * This loop is known to work with PHP 5.4 through PHP 7+.
+ *
+ * @see http://php.net/manual/en/book.ev.php
+ * @see https://bitbucket.org/osmanov/pecl-ev/overview
+ */
+class ExtEvLoop implements LoopInterface
+{
+ /**
+ * @var EvLoop
+ */
+ private $loop;
+
+ /**
+ * @var FutureTickQueue
+ */
+ private $futureTickQueue;
+
+ /**
+ * @var SplObjectStorage
+ */
+ private $timers;
+
+ /**
+ * @var EvIo[]
+ */
+ private $readStreams = [];
+
+ /**
+ * @var EvIo[]
+ */
+ private $writeStreams = [];
+
+ /**
+ * @var bool
+ */
+ private $running;
+
+ /**
+ * @var SignalsHandler
+ */
+ private $signals;
+
+ /**
+ * @var \EvSignal[]
+ */
+ private $signalEvents = [];
+
+ public function __construct()
+ {
+ $this->loop = new EvLoop();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timers = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int)$stream;
+
+ if (isset($this->readStreams[$key])) {
+ return;
+ }
+
+ $callback = $this->getStreamListenerClosure($stream, $listener);
+ $event = $this->loop->io($stream, Ev::READ, $callback);
+ $this->readStreams[$key] = $event;
+ }
+
+ /**
+ * @param resource $stream
+ * @param callable $listener
+ *
+ * @return \Closure
+ */
+ private function getStreamListenerClosure($stream, $listener)
+ {
+ return function () use ($stream, $listener) {
+ call_user_func($listener, $stream);
+ };
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int)$stream;
+
+ if (isset($this->writeStreams[$key])) {
+ return;
+ }
+
+ $callback = $this->getStreamListenerClosure($stream, $listener);
+ $event = $this->loop->io($stream, Ev::WRITE, $callback);
+ $this->writeStreams[$key] = $event;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int)$stream;
+
+ if (!isset($this->readStreams[$key])) {
+ return;
+ }
+
+ $this->readStreams[$key]->stop();
+ unset($this->readStreams[$key]);
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int)$stream;
+
+ if (!isset($this->writeStreams[$key])) {
+ return;
+ }
+
+ $this->writeStreams[$key]->stop();
+ unset($this->writeStreams[$key]);
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $that = $this;
+ $timers = $this->timers;
+ $callback = function () use ($timer, $timers, $that) {
+ call_user_func($timer->getCallback(), $timer);
+
+ if ($timers->contains($timer)) {
+ $that->cancelTimer($timer);
+ }
+ };
+
+ $event = $this->loop->timer($timer->getInterval(), 0.0, $callback);
+ $this->timers->attach($timer, $event);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $callback = function () use ($timer) {
+ call_user_func($timer->getCallback(), $timer);
+ };
+
+ $event = $this->loop->timer($interval, $interval, $callback);
+ $this->timers->attach($timer, $event);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if (!isset($this->timers[$timer])) {
+ return;
+ }
+
+ $event = $this->timers[$timer];
+ $event->stop();
+ $this->timers->detach($timer);
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
+ $wasJustStopped = !$this->running;
+ $nothingLeftToDo = !$this->readStreams
+ && !$this->writeStreams
+ && !$this->timers->count()
+ && $this->signals->isEmpty();
+
+ $flags = Ev::RUN_ONCE;
+ if ($wasJustStopped || $hasPendingCallbacks) {
+ $flags |= Ev::RUN_NOWAIT;
+ } elseif ($nothingLeftToDo) {
+ break;
+ }
+
+ $this->loop->run($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ public function __destruct()
+ {
+ /** @var TimerInterface $timer */
+ foreach ($this->timers as $timer) {
+ $this->cancelTimer($timer);
+ }
+
+ foreach ($this->readStreams as $key => $stream) {
+ $this->removeReadStream($key);
+ }
+
+ foreach ($this->writeStreams as $key => $stream) {
+ $this->removeWriteStream($key);
+ }
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = $this->loop->signal($signal, function() use ($signal) {
+ $this->signals->call($signal);
+ });
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal]->stop();
+ unset($this->signalEvents[$signal]);
+ }
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/ExtEventLoop.php b/assets/php/vendor/react/event-loop/src/ExtEventLoop.php
new file mode 100644
index 0000000..622dd47
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/ExtEventLoop.php
@@ -0,0 +1,259 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use Event;
+use EventBase;
+use EventConfig as EventBaseConfig;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-event` based event loop.
+ *
+ * This uses the [`event` PECL extension](https://pecl.php.net/package/event).
+ * It supports the same backends as libevent.
+ *
+ * This loop is known to work with PHP 5.4 through PHP 7+.
+ *
+ * @link https://pecl.php.net/package/event
+ */
+final class ExtEventLoop implements LoopInterface
+{
+ private $eventBase;
+ private $futureTickQueue;
+ private $timerCallback;
+ private $timerEvents;
+ private $streamCallback;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $readListeners = array();
+ private $writeListeners = array();
+ private $readRefs = array();
+ private $writeRefs = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!class_exists('EventBase', false)) {
+ throw new BadMethodCallException('Cannot create ExtEventLoop, ext-event extension missing');
+ }
+
+ $config = new EventBaseConfig();
+ $config->requireFeatures(EventBaseConfig::FEATURE_FDS);
+
+ $this->eventBase = new EventBase($config);
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+
+ $this->createTimerCallback();
+ $this->createStreamCallback();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->readListeners[$key])) {
+ return;
+ }
+
+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::READ, $this->streamCallback);
+ $event->add();
+ $this->readEvents[$key] = $event;
+ $this->readListeners[$key] = $listener;
+
+ // ext-event does not increase refcount on stream resources for PHP 7+
+ // manually keep track of stream resource to prevent premature garbage collection
+ if (PHP_VERSION_ID >= 70000) {
+ $this->readRefs[$key] = $stream;
+ }
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->writeListeners[$key])) {
+ return;
+ }
+
+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::WRITE, $this->streamCallback);
+ $event->add();
+ $this->writeEvents[$key] = $event;
+ $this->writeListeners[$key] = $listener;
+
+ // ext-event does not increase refcount on stream resources for PHP 7+
+ // manually keep track of stream resource to prevent premature garbage collection
+ if (PHP_VERSION_ID >= 70000) {
+ $this->writeRefs[$key] = $stream;
+ }
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readEvents[$key])) {
+ $this->readEvents[$key]->free();
+ unset(
+ $this->readEvents[$key],
+ $this->readListeners[$key],
+ $this->readRefs[$key]
+ );
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeEvents[$key])) {
+ $this->writeEvents[$key]->free();
+ unset(
+ $this->writeEvents[$key],
+ $this->writeListeners[$key],
+ $this->writeRefs[$key]
+ );
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if ($this->timerEvents->contains($timer)) {
+ $this->timerEvents[$timer]->free();
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = Event::signal($this->eventBase, $signal, array($this->signals, 'call'));
+ $this->signalEvents[$signal]->add();
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ $this->signalEvents[$signal]->free();
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = EventBase::LOOP_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= EventBase::LOOP_NONBLOCK;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ $this->eventBase->loop($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Schedule a timer for execution.
+ *
+ * @param TimerInterface $timer
+ */
+ private function scheduleTimer(TimerInterface $timer)
+ {
+ $flags = Event::TIMEOUT;
+
+ if ($timer->isPeriodic()) {
+ $flags |= Event::PERSIST;
+ }
+
+ $event = new Event($this->eventBase, -1, $flags, $this->timerCallback, $timer);
+ $this->timerEvents[$timer] = $event;
+
+ $event->add($timer->getInterval());
+ }
+
+ /**
+ * Create a callback used as the target of timer events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createTimerCallback()
+ {
+ $timers = $this->timerEvents;
+ $this->timerCallback = function ($_, $__, $timer) use ($timers) {
+ call_user_func($timer->getCallback(), $timer);
+
+ if (!$timer->isPeriodic() && $timers->contains($timer)) {
+ $this->cancelTimer($timer);
+ }
+ };
+ }
+
+ /**
+ * Create a callback used as the target of stream events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createStreamCallback()
+ {
+ $read =& $this->readListeners;
+ $write =& $this->writeListeners;
+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
+ $key = (int) $stream;
+
+ if (Event::READ === (Event::READ & $flags) && isset($read[$key])) {
+ call_user_func($read[$key], $stream);
+ }
+
+ if (Event::WRITE === (Event::WRITE & $flags) && isset($write[$key])) {
+ call_user_func($write[$key], $stream);
+ }
+ };
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/ExtLibevLoop.php b/assets/php/vendor/react/event-loop/src/ExtLibevLoop.php
new file mode 100644
index 0000000..d3b0df8
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/ExtLibevLoop.php
@@ -0,0 +1,199 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use libev\EventLoop;
+use libev\IOEvent;
+use libev\SignalEvent;
+use libev\TimerEvent;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-libev` based event loop.
+ *
+ * This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev).
+ * It supports the same backends as libevent.
+ *
+ * This loop does only work with PHP 5.
+ * An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
+ * to happen any time soon.
+ *
+ * @see https://github.com/m4rw3r/php-libev
+ * @see https://gist.github.com/1688204
+ */
+final class ExtLibevLoop implements LoopInterface
+{
+ private $loop;
+ private $futureTickQueue;
+ private $timerEvents;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!class_exists('libev\EventLoop', false)) {
+ throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing');
+ }
+
+ $this->loop = new EventLoop();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ if (isset($this->readEvents[(int) $stream])) {
+ return;
+ }
+
+ $callback = function () use ($stream, $listener) {
+ call_user_func($listener, $stream);
+ };
+
+ $event = new IOEvent($callback, $stream, IOEvent::READ);
+ $this->loop->add($event);
+
+ $this->readEvents[(int) $stream] = $event;
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ if (isset($this->writeEvents[(int) $stream])) {
+ return;
+ }
+
+ $callback = function () use ($stream, $listener) {
+ call_user_func($listener, $stream);
+ };
+
+ $event = new IOEvent($callback, $stream, IOEvent::WRITE);
+ $this->loop->add($event);
+
+ $this->writeEvents[(int) $stream] = $event;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readEvents[$key])) {
+ $this->readEvents[$key]->stop();
+ $this->loop->remove($this->readEvents[$key]);
+ unset($this->readEvents[$key]);
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeEvents[$key])) {
+ $this->writeEvents[$key]->stop();
+ $this->loop->remove($this->writeEvents[$key]);
+ unset($this->writeEvents[$key]);
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer( $interval, $callback, false);
+
+ $that = $this;
+ $timers = $this->timerEvents;
+ $callback = function () use ($timer, $timers, $that) {
+ call_user_func($timer->getCallback(), $timer);
+
+ if ($timers->contains($timer)) {
+ $that->cancelTimer($timer);
+ }
+ };
+
+ $event = new TimerEvent($callback, $timer->getInterval());
+ $this->timerEvents->attach($timer, $event);
+ $this->loop->add($event);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $callback = function () use ($timer) {
+ call_user_func($timer->getCallback(), $timer);
+ };
+
+ $event = new TimerEvent($callback, $interval, $interval);
+ $this->timerEvents->attach($timer, $event);
+ $this->loop->add($event);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if (isset($this->timerEvents[$timer])) {
+ $this->loop->remove($this->timerEvents[$timer]);
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $signals = $this->signals;
+ $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) {
+ $signals->call($signal);
+ }, $signal);
+ $this->loop->add($this->signalEvents[$signal]);
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ $this->signalEvents[$signal]->stop();
+ $this->loop->remove($this->signalEvents[$signal]);
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = EventLoop::RUN_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= EventLoop::RUN_NOWAIT;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ $this->loop->run($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/ExtLibeventLoop.php b/assets/php/vendor/react/event-loop/src/ExtLibeventLoop.php
new file mode 100644
index 0000000..427f8db
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/ExtLibeventLoop.php
@@ -0,0 +1,283 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use Event;
+use EventBase;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-libevent` based event loop.
+ *
+ * This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent).
+ * `libevent` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This event loop does only work with PHP 5.
+ * An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for
+ * PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s.
+ * To reiterate: Using this event loop on PHP 7 is not recommended.
+ * Accordingly, the [`Factory`](#factory) will not try to use this event loop on
+ * PHP 7.
+ *
+ * This event loop is known to trigger a readable listener only if
+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
+ * stream has already been readable from the beginning.
+ * This also implies that a stream may not be recognized as readable when data
+ * is still left in PHP's internal stream buffers.
+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
+ * to disable PHP's internal read buffer in this case.
+ * See also [`addReadStream()`](#addreadstream) for more details.
+ *
+ * @link https://pecl.php.net/package/libevent
+ */
+final class ExtLibeventLoop implements LoopInterface
+{
+ /** @internal */
+ const MICROSECONDS_PER_SECOND = 1000000;
+
+ private $eventBase;
+ private $futureTickQueue;
+ private $timerCallback;
+ private $timerEvents;
+ private $streamCallback;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $readListeners = array();
+ private $writeListeners = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!function_exists('event_base_new')) {
+ throw new BadMethodCallException('Cannot create ExtLibeventLoop, ext-libevent extension missing');
+ }
+
+ $this->eventBase = event_base_new();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+
+ $this->createTimerCallback();
+ $this->createStreamCallback();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->readListeners[$key])) {
+ return;
+ }
+
+ $event = event_new();
+ event_set($event, $stream, EV_PERSIST | EV_READ, $this->streamCallback);
+ event_base_set($event, $this->eventBase);
+ event_add($event);
+
+ $this->readEvents[$key] = $event;
+ $this->readListeners[$key] = $listener;
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->writeListeners[$key])) {
+ return;
+ }
+
+ $event = event_new();
+ event_set($event, $stream, EV_PERSIST | EV_WRITE, $this->streamCallback);
+ event_base_set($event, $this->eventBase);
+ event_add($event);
+
+ $this->writeEvents[$key] = $event;
+ $this->writeListeners[$key] = $listener;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readListeners[$key])) {
+ $event = $this->readEvents[$key];
+ event_del($event);
+ event_free($event);
+
+ unset(
+ $this->readEvents[$key],
+ $this->readListeners[$key]
+ );
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeListeners[$key])) {
+ $event = $this->writeEvents[$key];
+ event_del($event);
+ event_free($event);
+
+ unset(
+ $this->writeEvents[$key],
+ $this->writeListeners[$key]
+ );
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if ($this->timerEvents->contains($timer)) {
+ $event = $this->timerEvents[$timer];
+ event_del($event);
+ event_free($event);
+
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = event_new();
+ event_set($this->signalEvents[$signal], $signal, EV_PERSIST | EV_SIGNAL, array($this->signals, 'call'));
+ event_base_set($this->signalEvents[$signal], $this->eventBase);
+ event_add($this->signalEvents[$signal]);
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ event_del($this->signalEvents[$signal]);
+ event_free($this->signalEvents[$signal]);
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = EVLOOP_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= EVLOOP_NONBLOCK;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ event_base_loop($this->eventBase, $flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Schedule a timer for execution.
+ *
+ * @param TimerInterface $timer
+ */
+ private function scheduleTimer(TimerInterface $timer)
+ {
+ $this->timerEvents[$timer] = $event = event_timer_new();
+
+ event_timer_set($event, $this->timerCallback, $timer);
+ event_base_set($event, $this->eventBase);
+ event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND);
+ }
+
+ /**
+ * Create a callback used as the target of timer events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createTimerCallback()
+ {
+ $that = $this;
+ $timers = $this->timerEvents;
+ $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) {
+ call_user_func($timer->getCallback(), $timer);
+
+ // Timer already cancelled ...
+ if (!$timers->contains($timer)) {
+ return;
+ }
+
+ // Reschedule periodic timers ...
+ if ($timer->isPeriodic()) {
+ event_add(
+ $timers[$timer],
+ $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND
+ );
+
+ // Clean-up one shot timers ...
+ } else {
+ $that->cancelTimer($timer);
+ }
+ };
+ }
+
+ /**
+ * Create a callback used as the target of stream events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createStreamCallback()
+ {
+ $read =& $this->readListeners;
+ $write =& $this->writeListeners;
+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
+ $key = (int) $stream;
+
+ if (EV_READ === (EV_READ & $flags) && isset($read[$key])) {
+ call_user_func($read[$key], $stream);
+ }
+
+ if (EV_WRITE === (EV_WRITE & $flags) && isset($write[$key])) {
+ call_user_func($write[$key], $stream);
+ }
+ };
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/Factory.php b/assets/php/vendor/react/event-loop/src/Factory.php
new file mode 100644
index 0000000..b46fc07
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/Factory.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace React\EventLoop;
+
+/**
+ * The `Factory` class exists as a convenient way to pick the best available event loop implementation.
+ */
+final class Factory
+{
+ /**
+ * Creates a new event loop instance
+ *
+ * ```php
+ * $loop = React\EventLoop\Factory::create();
+ * ```
+ *
+ * This method always returns an instance implementing `LoopInterface`,
+ * the actual event loop implementation is an implementation detail.
+ *
+ * This method should usually only be called once at the beginning of the program.
+ *
+ * @return LoopInterface
+ */
+ public static function create()
+ {
+ // @codeCoverageIgnoreStart
+ if (class_exists('libev\EventLoop', false)) {
+ return new ExtLibevLoop();
+ } elseif (class_exists('EvLoop', false)) {
+ return new ExtEvLoop();
+ } elseif (class_exists('EventBase', false)) {
+ return new ExtEventLoop();
+ } elseif (function_exists('event_base_new') && PHP_VERSION_ID < 70000) {
+ // only use ext-libevent on PHP < 7 for now
+ return new ExtLibeventLoop();
+ }
+
+ return new StreamSelectLoop();
+ // @codeCoverageIgnoreEnd
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/LoopInterface.php b/assets/php/vendor/react/event-loop/src/LoopInterface.php
new file mode 100644
index 0000000..1cc8640
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/LoopInterface.php
@@ -0,0 +1,463 @@
+<?php
+
+namespace React\EventLoop;
+
+interface LoopInterface
+{
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to read.
+ *
+ * Note that this low-level API is considered advanced usage.
+ * Most use cases should probably use the higher-level
+ * [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
+ * instead.
+ *
+ * The first parameter MUST be a valid stream resource that supports
+ * checking whether it is ready to read by this loop implementation.
+ * A single stream resource MUST NOT be added more than once.
+ * Instead, either call [`removeReadStream()`](#removereadstream) first or
+ * react to this event with a single listener and then dispatch from this
+ * listener. This method MAY throw an `Exception` if the given resource type
+ * is not supported by this loop implementation.
+ *
+ * The listener callback function MUST be able to accept a single parameter,
+ * the stream resource added by this method or you MAY use a function which
+ * has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * $loop->addReadStream($stream, function ($stream) use ($name) {
+ * echo $name . ' said: ' . fread($stream);
+ * });
+ * ```
+ *
+ * See also [example #11](examples).
+ *
+ * You can invoke [`removeReadStream()`](#removereadstream) to remove the
+ * read event listener for this stream.
+ *
+ * The execution order of listeners when multiple streams become ready at
+ * the same time is not guaranteed.
+ *
+ * @param resource $stream The PHP stream resource to check.
+ * @param callable $listener Invoked when the stream is ready.
+ * @throws \Exception if the given resource type is not supported by this loop implementation
+ * @see self::removeReadStream()
+ */
+ public function addReadStream($stream, $listener);
+
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to write.
+ *
+ * Note that this low-level API is considered advanced usage.
+ * Most use cases should probably use the higher-level
+ * [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
+ * instead.
+ *
+ * The first parameter MUST be a valid stream resource that supports
+ * checking whether it is ready to write by this loop implementation.
+ * A single stream resource MUST NOT be added more than once.
+ * Instead, either call [`removeWriteStream()`](#removewritestream) first or
+ * react to this event with a single listener and then dispatch from this
+ * listener. This method MAY throw an `Exception` if the given resource type
+ * is not supported by this loop implementation.
+ *
+ * The listener callback function MUST be able to accept a single parameter,
+ * the stream resource added by this method or you MAY use a function which
+ * has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * $loop->addWriteStream($stream, function ($stream) use ($name) {
+ * fwrite($stream, 'Hello ' . $name);
+ * });
+ * ```
+ *
+ * See also [example #12](examples).
+ *
+ * You can invoke [`removeWriteStream()`](#removewritestream) to remove the
+ * write event listener for this stream.
+ *
+ * The execution order of listeners when multiple streams become ready at
+ * the same time is not guaranteed.
+ *
+ * Some event loop implementations are known to only trigger the listener if
+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
+ * stream has already been readable from the beginning.
+ * This also implies that a stream may not be recognized as readable when data
+ * is still left in PHP's internal stream buffers.
+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
+ * to disable PHP's internal read buffer in this case.
+ *
+ * @param resource $stream The PHP stream resource to check.
+ * @param callable $listener Invoked when the stream is ready.
+ * @throws \Exception if the given resource type is not supported by this loop implementation
+ * @see self::removeWriteStream()
+ */
+ public function addWriteStream($stream, $listener);
+
+ /**
+ * Remove the read event listener for the given stream.
+ *
+ * Removing a stream from the loop that has already been removed or trying
+ * to remove a stream that was never added or is invalid has no effect.
+ *
+ * @param resource $stream The PHP stream resource.
+ */
+ public function removeReadStream($stream);
+
+ /**
+ * Remove the write event listener for the given stream.
+ *
+ * Removing a stream from the loop that has already been removed or trying
+ * to remove a stream that was never added or is invalid has no effect.
+ *
+ * @param resource $stream The PHP stream resource.
+ */
+ public function removeWriteStream($stream);
+
+ /**
+ * Enqueue a callback to be invoked once after the given interval.
+ *
+ * The timer callback function MUST be able to accept a single parameter,
+ * the timer instance as also returned by this method or you MAY use a
+ * function which has no parameters at all.
+ *
+ * The timer callback function MUST NOT throw an `Exception`.
+ * The return value of the timer callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
+ * the callback will be invoked only once after the given interval.
+ * You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
+ *
+ * ```php
+ * $loop->addTimer(0.8, function () {
+ * echo 'world!' . PHP_EOL;
+ * });
+ *
+ * $loop->addTimer(0.3, function () {
+ * echo 'hello ';
+ * });
+ * ```
+ *
+ * See also [example #1](examples).
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $loop->addTimer(1.0, function () use ($name) {
+ * echo "hello $name\n";
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * This interface does not enforce any particular timer resolution, so
+ * special care may have to be taken if you rely on very high precision with
+ * millisecond accuracy or below. Event loop implementations SHOULD work on
+ * a best effort basis and SHOULD provide at least millisecond accuracy
+ * unless otherwise noted. Many existing event loop implementations are
+ * known to provide microsecond accuracy, but it's generally not recommended
+ * to rely on this high precision.
+ *
+ * Similarly, the execution order of timers scheduled to execute at the
+ * same time (within its possible accuracy) is not guaranteed.
+ *
+ * This interface suggests that event loop implementations SHOULD use a
+ * monotonic time source if available. Given that a monotonic time source is
+ * not available on PHP by default, event loop implementations MAY fall back
+ * to using wall-clock time.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s and then adjust
+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
+ * See also [event loop implementations](#loop-implementations) for more details.
+ *
+ * @param int|float $interval The number of seconds to wait before execution.
+ * @param callable $callback The callback to invoke.
+ *
+ * @return TimerInterface
+ */
+ public function addTimer($interval, $callback);
+
+ /**
+ * Enqueue a callback to be invoked repeatedly after the given interval.
+ *
+ * The timer callback function MUST be able to accept a single parameter,
+ * the timer instance as also returned by this method or you MAY use a
+ * function which has no parameters at all.
+ *
+ * The timer callback function MUST NOT throw an `Exception`.
+ * The return value of the timer callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * Unlike [`addTimer()`](#addtimer), this method will ensure the the
+ * callback will be invoked infinitely after the given interval or until you
+ * invoke [`cancelTimer`](#canceltimer).
+ *
+ * ```php
+ * $timer = $loop->addPeriodicTimer(0.1, function () {
+ * echo 'tick!' . PHP_EOL;
+ * });
+ *
+ * $loop->addTimer(1.0, function () use ($loop, $timer) {
+ * $loop->cancelTimer($timer);
+ * echo 'Done' . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [example #2](examples).
+ *
+ * If you want to limit the number of executions, you can bind
+ * arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $n = 3;
+ * $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
+ * if ($n > 0) {
+ * --$n;
+ * echo "hello $name\n";
+ * } else {
+ * $loop->cancelTimer($timer);
+ * }
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * This interface does not enforce any particular timer resolution, so
+ * special care may have to be taken if you rely on very high precision with
+ * millisecond accuracy or below. Event loop implementations SHOULD work on
+ * a best effort basis and SHOULD provide at least millisecond accuracy
+ * unless otherwise noted. Many existing event loop implementations are
+ * known to provide microsecond accuracy, but it's generally not recommended
+ * to rely on this high precision.
+ *
+ * Similarly, the execution order of timers scheduled to execute at the
+ * same time (within its possible accuracy) is not guaranteed.
+ *
+ * This interface suggests that event loop implementations SHOULD use a
+ * monotonic time source if available. Given that a monotonic time source is
+ * not available on PHP by default, event loop implementations MAY fall back
+ * to using wall-clock time.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s and then adjust
+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
+ * See also [event loop implementations](#loop-implementations) for more details.
+ *
+ * Additionally, periodic timers may be subject to timer drift due to
+ * re-scheduling after each invocation. As such, it's generally not
+ * recommended to rely on this for high precision intervals with millisecond
+ * accuracy or below.
+ *
+ * @param int|float $interval The number of seconds to wait before execution.
+ * @param callable $callback The callback to invoke.
+ *
+ * @return TimerInterface
+ */
+ public function addPeriodicTimer($interval, $callback);
+
+ /**
+ * Cancel a pending timer.
+ *
+ * See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
+ *
+ * Calling this method on a timer instance that has not been added to this
+ * loop instance or on a timer that has already been cancelled has no effect.
+ *
+ * @param TimerInterface $timer The timer to cancel.
+ *
+ * @return void
+ */
+ public function cancelTimer(TimerInterface $timer);
+
+ /**
+ * Schedule a callback to be invoked on a future tick of the event loop.
+ *
+ * This works very much similar to timers with an interval of zero seconds,
+ * but does not require the overhead of scheduling a timer queue.
+ *
+ * The tick callback function MUST be able to accept zero parameters.
+ *
+ * The tick callback function MUST NOT throw an `Exception`.
+ * The return value of the tick callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $loop->futureTick(function () use ($name) {
+ * echo "hello $name\n";
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * Unlike timers, tick callbacks are guaranteed to be executed in the order
+ * they are enqueued.
+ * Also, once a callback is enqueued, there's no way to cancel this operation.
+ *
+ * This is often used to break down bigger tasks into smaller steps (a form
+ * of cooperative multitasking).
+ *
+ * ```php
+ * $loop->futureTick(function () {
+ * echo 'b';
+ * });
+ * $loop->futureTick(function () {
+ * echo 'c';
+ * });
+ * echo 'a';
+ * ```
+ *
+ * See also [example #3](examples).
+ *
+ * @param callable $listener The callback to invoke.
+ *
+ * @return void
+ */
+ public function futureTick($listener);
+
+ /**
+ * Register a listener to be notified when a signal has been caught by this process.
+ *
+ * This is useful to catch user interrupt signals or shutdown signals from
+ * tools like `supervisor` or `systemd`.
+ *
+ * The listener callback function MUST be able to accept a single parameter,
+ * the signal added by this method or you MAY use a function which
+ * has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * ```php
+ * $loop->addSignal(SIGINT, function (int $signal) {
+ * echo 'Caught user interrupt signal' . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [example #4](examples).
+ *
+ * Signaling is only available on Unix-like platform, Windows isn't
+ * supported due to operating system limitations.
+ * This method may throw a `BadMethodCallException` if signals aren't
+ * supported on this platform, for example when required extensions are
+ * missing.
+ *
+ * **Note: A listener can only be added once to the same signal, any
+ * attempts to add it more then once will be ignored.**
+ *
+ * @param int $signal
+ * @param callable $listener
+ *
+ * @throws \BadMethodCallException when signals aren't supported on this
+ * platform, for example when required extensions are missing.
+ *
+ * @return void
+ */
+ public function addSignal($signal, $listener);
+
+ /**
+ * Removes a previously added signal listener.
+ *
+ * ```php
+ * $loop->removeSignal(SIGINT, $listener);
+ * ```
+ *
+ * Any attempts to remove listeners that aren't registered will be ignored.
+ *
+ * @param int $signal
+ * @param callable $listener
+ *
+ * @return void
+ */
+ public function removeSignal($signal, $listener);
+
+ /**
+ * Run the event loop until there are no more tasks to perform.
+ *
+ * For many applications, this method is the only directly visible
+ * invocation on the event loop.
+ * As a rule of thumb, it is usally recommended to attach everything to the
+ * same loop instance and then run the loop once at the bottom end of the
+ * application.
+ *
+ * ```php
+ * $loop->run();
+ * ```
+ *
+ * This method will keep the loop running until there are no more tasks
+ * to perform. In other words: This method will block until the last
+ * timer, stream and/or signal has been removed.
+ *
+ * Likewise, it is imperative to ensure the application actually invokes
+ * this method once. Adding listeners to the loop and missing to actually
+ * run it will result in the application exiting without actually waiting
+ * for any of the attached listeners.
+ *
+ * This method MUST NOT be called while the loop is already running.
+ * This method MAY be called more than once after it has explicity been
+ * [`stop()`ped](#stop) or after it automatically stopped because it
+ * previously did no longer have anything to do.
+ *
+ * @return void
+ */
+ public function run();
+
+ /**
+ * Instruct a running event loop to stop.
+ *
+ * This method is considered advanced usage and should be used with care.
+ * As a rule of thumb, it is usually recommended to let the loop stop
+ * only automatically when it no longer has anything to do.
+ *
+ * This method can be used to explicitly instruct the event loop to stop:
+ *
+ * ```php
+ * $loop->addTimer(3.0, function () use ($loop) {
+ * $loop->stop();
+ * });
+ * ```
+ *
+ * Calling this method on a loop instance that is not currently running or
+ * on a loop instance that has already been stopped has no effect.
+ *
+ * @return void
+ */
+ public function stop();
+}
diff --git a/assets/php/vendor/react/event-loop/src/SignalsHandler.php b/assets/php/vendor/react/event-loop/src/SignalsHandler.php
new file mode 100644
index 0000000..523e1ca
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/SignalsHandler.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace React\EventLoop;
+
+/**
+ * @internal
+ */
+final class SignalsHandler
+{
+ private $signals = array();
+
+ public function add($signal, $listener)
+ {
+ if (!isset($this->signals[$signal])) {
+ $this->signals[$signal] = array();
+ }
+
+ if (in_array($listener, $this->signals[$signal])) {
+ return;
+ }
+
+ $this->signals[$signal][] = $listener;
+ }
+
+ public function remove($signal, $listener)
+ {
+ if (!isset($this->signals[$signal])) {
+ return;
+ }
+
+ $index = \array_search($listener, $this->signals[$signal], true);
+ unset($this->signals[$signal][$index]);
+
+ if (isset($this->signals[$signal]) && \count($this->signals[$signal]) === 0) {
+ unset($this->signals[$signal]);
+ }
+ }
+
+ public function call($signal)
+ {
+ if (!isset($this->signals[$signal])) {
+ return;
+ }
+
+ foreach ($this->signals[$signal] as $listener) {
+ \call_user_func($listener, $signal);
+ }
+ }
+
+ public function count($signal)
+ {
+ if (!isset($this->signals[$signal])) {
+ return 0;
+ }
+
+ return \count($this->signals[$signal]);
+ }
+
+ public function isEmpty()
+ {
+ return !$this->signals;
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/StreamSelectLoop.php b/assets/php/vendor/react/event-loop/src/StreamSelectLoop.php
new file mode 100644
index 0000000..e82e9e4
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/StreamSelectLoop.php
@@ -0,0 +1,275 @@
+<?php
+
+namespace React\EventLoop;
+
+use React\EventLoop\Signal\Pcntl;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use React\EventLoop\Timer\Timers;
+
+/**
+ * A `stream_select()` based event loop.
+ *
+ * This uses the [`stream_select()`](http://php.net/manual/en/function.stream-select.php)
+ * function and is the only implementation which works out of the box with PHP.
+ *
+ * This event loop works out of the box on PHP 5.4 through PHP 7+ and HHVM.
+ * This means that no installation is required and this library works on all
+ * platforms and supported PHP versions.
+ * Accordingly, the [`Factory`](#factory) will use this event loop by default if
+ * you do not install any of the event loop extensions listed below.
+ *
+ * Under the hood, it does a simple `select` system call.
+ * This system call is limited to the maximum file descriptor number of
+ * `FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`
+ * (`m` being the maximum file descriptor number passed).
+ * This means that you may run into issues when handling thousands of streams
+ * concurrently and you may want to look into using one of the alternative
+ * event loop implementations listed below in this case.
+ * If your use case is among the many common use cases that involve handling only
+ * dozens or a few hundred streams at once, then this event loop implementation
+ * performs really well.
+ *
+ * If you want to use signal handling (see also [`addSignal()`](#addsignal) below),
+ * this event loop implementation requires `ext-pcntl`.
+ * This extension is only available for Unix-like platforms and does not support
+ * Windows.
+ * It is commonly installed as part of many PHP distributions.
+ * If this extension is missing (or you're running on Windows), signal handling is
+ * not supported and throws a `BadMethodCallException` instead.
+ *
+ * This event loop is known to rely on wall-clock time to schedule future
+ * timers, because a monotonic time source is not available in PHP by default.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s and then adjust
+ * your system time forward by 20s, the timer may trigger in 10s.
+ * See also [`addTimer()`](#addtimer) for more details.
+ *
+ * @link http://php.net/manual/en/function.stream-select.php
+ */
+final class StreamSelectLoop implements LoopInterface
+{
+ /** @internal */
+ const MICROSECONDS_PER_SECOND = 1000000;
+
+ private $futureTickQueue;
+ private $timers;
+ private $readStreams = array();
+ private $readListeners = array();
+ private $writeStreams = array();
+ private $writeListeners = array();
+ private $running;
+ private $pcntl = false;
+ private $signals;
+
+ public function __construct()
+ {
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timers = new Timers();
+ $this->pcntl = extension_loaded('pcntl');
+ $this->signals = new SignalsHandler();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+
+ if (!isset($this->readStreams[$key])) {
+ $this->readStreams[$key] = $stream;
+ $this->readListeners[$key] = $listener;
+ }
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+
+ if (!isset($this->writeStreams[$key])) {
+ $this->writeStreams[$key] = $stream;
+ $this->writeListeners[$key] = $listener;
+ }
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ unset(
+ $this->readStreams[$key],
+ $this->readListeners[$key]
+ );
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ unset(
+ $this->writeStreams[$key],
+ $this->writeListeners[$key]
+ );
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->timers->add($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->timers->add($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ $this->timers->cancel($timer);
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ if ($this->pcntl === false) {
+ throw new \BadMethodCallException('Event loop feature "signals" isn\'t supported by the "StreamSelectLoop"');
+ }
+
+ $first = $this->signals->count($signal) === 0;
+ $this->signals->add($signal, $listener);
+
+ if ($first) {
+ \pcntl_signal($signal, array($this->signals, 'call'));
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ if (!$this->signals->count($signal)) {
+ return;
+ }
+
+ $this->signals->remove($signal, $listener);
+
+ if ($this->signals->count($signal) === 0) {
+ \pcntl_signal($signal, SIG_DFL);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $this->timers->tick();
+
+ // Future-tick queue has pending callbacks ...
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $timeout = 0;
+
+ // There is a pending timer, only block until it is due ...
+ } elseif ($scheduledAt = $this->timers->getFirst()) {
+ $timeout = $scheduledAt - $this->timers->getTime();
+ if ($timeout < 0) {
+ $timeout = 0;
+ } else {
+ // Convert float seconds to int microseconds.
+ // Ensure we do not exceed maximum integer size, which may
+ // cause the loop to tick once every ~35min on 32bit systems.
+ $timeout *= self::MICROSECONDS_PER_SECOND;
+ $timeout = $timeout > PHP_INT_MAX ? PHP_INT_MAX : (int)$timeout;
+ }
+
+ // The only possible event is stream or signal activity, so wait forever ...
+ } elseif ($this->readStreams || $this->writeStreams || !$this->signals->isEmpty()) {
+ $timeout = null;
+
+ // There's nothing left to do ...
+ } else {
+ break;
+ }
+
+ $this->waitForStreamActivity($timeout);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Wait/check for stream activity, or until the next timer is due.
+ *
+ * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
+ */
+ private function waitForStreamActivity($timeout)
+ {
+ $read = $this->readStreams;
+ $write = $this->writeStreams;
+
+ $available = $this->streamSelect($read, $write, $timeout);
+ if ($this->pcntl) {
+ \pcntl_signal_dispatch();
+ }
+ if (false === $available) {
+ // if a system call has been interrupted,
+ // we cannot rely on it's outcome
+ return;
+ }
+
+ foreach ($read as $stream) {
+ $key = (int) $stream;
+
+ if (isset($this->readListeners[$key])) {
+ call_user_func($this->readListeners[$key], $stream);
+ }
+ }
+
+ foreach ($write as $stream) {
+ $key = (int) $stream;
+
+ if (isset($this->writeListeners[$key])) {
+ call_user_func($this->writeListeners[$key], $stream);
+ }
+ }
+ }
+
+ /**
+ * Emulate a stream_select() implementation that does not break when passed
+ * empty stream arrays.
+ *
+ * @param array &$read An array of read streams to select upon.
+ * @param array &$write An array of write streams to select upon.
+ * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
+ *
+ * @return integer|false The total number of streams that are ready for read/write.
+ * Can return false if stream_select() is interrupted by a signal.
+ */
+ private function streamSelect(array &$read, array &$write, $timeout)
+ {
+ if ($read || $write) {
+ $except = null;
+
+ // suppress warnings that occur, when stream_select is interrupted by a signal
+ return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout);
+ }
+
+ $timeout && usleep($timeout);
+
+ return 0;
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/Tick/FutureTickQueue.php b/assets/php/vendor/react/event-loop/src/Tick/FutureTickQueue.php
new file mode 100644
index 0000000..c79afc5
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/Tick/FutureTickQueue.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace React\EventLoop\Tick;
+
+use SplQueue;
+
+/**
+ * A tick queue implementation that can hold multiple callback functions
+ *
+ * This class should only be used internally, see LoopInterface instead.
+ *
+ * @see LoopInterface
+ * @internal
+ */
+final class FutureTickQueue
+{
+ private $queue;
+
+ public function __construct()
+ {
+ $this->queue = new SplQueue();
+ }
+
+ /**
+ * Add a callback to be invoked on a future tick of the event loop.
+ *
+ * Callbacks are guaranteed to be executed in the order they are enqueued.
+ *
+ * @param callable $listener The callback to invoke.
+ */
+ public function add($listener)
+ {
+ $this->queue->enqueue($listener);
+ }
+
+ /**
+ * Flush the callback queue.
+ */
+ public function tick()
+ {
+ // Only invoke as many callbacks as were on the queue when tick() was called.
+ $count = $this->queue->count();
+
+ while ($count--) {
+ call_user_func(
+ $this->queue->dequeue()
+ );
+ }
+ }
+
+ /**
+ * Check if the next tick queue is empty.
+ *
+ * @return boolean
+ */
+ public function isEmpty()
+ {
+ return $this->queue->isEmpty();
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/Timer/Timer.php b/assets/php/vendor/react/event-loop/src/Timer/Timer.php
new file mode 100644
index 0000000..da3602a
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/Timer/Timer.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace React\EventLoop\Timer;
+
+use React\EventLoop\TimerInterface;
+
+/**
+ * The actual connection implementation for TimerInterface
+ *
+ * This class should only be used internally, see TimerInterface instead.
+ *
+ * @see TimerInterface
+ * @internal
+ */
+final class Timer implements TimerInterface
+{
+ const MIN_INTERVAL = 0.000001;
+
+ private $interval;
+ private $callback;
+ private $periodic;
+
+ /**
+ * Constructor initializes the fields of the Timer
+ *
+ * @param float $interval The interval after which this timer will execute, in seconds
+ * @param callable $callback The callback that will be executed when this timer elapses
+ * @param bool $periodic Whether the time is periodic
+ */
+ public function __construct($interval, $callback, $periodic = false)
+ {
+ if ($interval < self::MIN_INTERVAL) {
+ $interval = self::MIN_INTERVAL;
+ }
+
+ $this->interval = (float) $interval;
+ $this->callback = $callback;
+ $this->periodic = (bool) $periodic;
+ }
+
+ public function getInterval()
+ {
+ return $this->interval;
+ }
+
+ public function getCallback()
+ {
+ return $this->callback;
+ }
+
+ public function isPeriodic()
+ {
+ return $this->periodic;
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/Timer/Timers.php b/assets/php/vendor/react/event-loop/src/Timer/Timers.php
new file mode 100644
index 0000000..17bbdac
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/Timer/Timers.php
@@ -0,0 +1,109 @@
+<?php
+
+namespace React\EventLoop\Timer;
+
+use React\EventLoop\TimerInterface;
+use SplObjectStorage;
+use SplPriorityQueue;
+
+/**
+ * A scheduler implementation that can hold multiple timer instances
+ *
+ * This class should only be used internally, see TimerInterface instead.
+ *
+ * @see TimerInterface
+ * @internal
+ */
+final class Timers
+{
+ private $time;
+ private $timers;
+ private $scheduler;
+
+ public function __construct()
+ {
+ $this->timers = new SplObjectStorage();
+ $this->scheduler = new SplPriorityQueue();
+ }
+
+ public function updateTime()
+ {
+ return $this->time = microtime(true);
+ }
+
+ public function getTime()
+ {
+ return $this->time ?: $this->updateTime();
+ }
+
+ public function add(TimerInterface $timer)
+ {
+ $interval = $timer->getInterval();
+ $scheduledAt = $interval + microtime(true);
+
+ $this->timers->attach($timer, $scheduledAt);
+ $this->scheduler->insert($timer, -$scheduledAt);
+ }
+
+ public function contains(TimerInterface $timer)
+ {
+ return $this->timers->contains($timer);
+ }
+
+ public function cancel(TimerInterface $timer)
+ {
+ $this->timers->detach($timer);
+ }
+
+ public function getFirst()
+ {
+ while ($this->scheduler->count()) {
+ $timer = $this->scheduler->top();
+
+ if ($this->timers->contains($timer)) {
+ return $this->timers[$timer];
+ }
+
+ $this->scheduler->extract();
+ }
+
+ return null;
+ }
+
+ public function isEmpty()
+ {
+ return count($this->timers) === 0;
+ }
+
+ public function tick()
+ {
+ $time = $this->updateTime();
+ $timers = $this->timers;
+ $scheduler = $this->scheduler;
+
+ while (!$scheduler->isEmpty()) {
+ $timer = $scheduler->top();
+
+ if (!isset($timers[$timer])) {
+ $scheduler->extract();
+ $timers->detach($timer);
+
+ continue;
+ }
+
+ if ($timers[$timer] >= $time) {
+ break;
+ }
+
+ $scheduler->extract();
+ call_user_func($timer->getCallback(), $timer);
+
+ if ($timer->isPeriodic() && isset($timers[$timer])) {
+ $timers[$timer] = $scheduledAt = $timer->getInterval() + $time;
+ $scheduler->insert($timer, -$scheduledAt);
+ } else {
+ $timers->detach($timer);
+ }
+ }
+ }
+}
diff --git a/assets/php/vendor/react/event-loop/src/TimerInterface.php b/assets/php/vendor/react/event-loop/src/TimerInterface.php
new file mode 100644
index 0000000..cdcf773
--- /dev/null
+++ b/assets/php/vendor/react/event-loop/src/TimerInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace React\EventLoop;
+
+interface TimerInterface
+{
+ /**
+ * Get the interval after which this timer will execute, in seconds
+ *
+ * @return float
+ */
+ public function getInterval();
+
+ /**
+ * Get the callback that will be executed when this timer elapses
+ *
+ * @return callable
+ */
+ public function getCallback();
+
+ /**
+ * Determine whether the time is periodic
+ *
+ * @return bool
+ */
+ public function isPeriodic();
+}