aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/event/lib
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/event/lib')
-rw-r--r--vendor/sabre/event/lib/EventEmitter.php18
-rw-r--r--vendor/sabre/event/lib/EventEmitterInterface.php100
-rw-r--r--vendor/sabre/event/lib/EventEmitterTrait.php211
-rw-r--r--vendor/sabre/event/lib/Loop/Loop.php386
-rw-r--r--vendor/sabre/event/lib/Loop/functions.php183
-rw-r--r--vendor/sabre/event/lib/Promise.php320
-rw-r--r--vendor/sabre/event/lib/Promise/functions.php135
-rw-r--r--vendor/sabre/event/lib/PromiseAlreadyResolvedException.php15
-rw-r--r--vendor/sabre/event/lib/Version.php19
-rw-r--r--vendor/sabre/event/lib/coroutine.php120
10 files changed, 1507 insertions, 0 deletions
diff --git a/vendor/sabre/event/lib/EventEmitter.php b/vendor/sabre/event/lib/EventEmitter.php
new file mode 100644
index 000000000..1bb1c3cf9
--- /dev/null
+++ b/vendor/sabre/event/lib/EventEmitter.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Sabre\Event;
+
+/**
+ * EventEmitter object.
+ *
+ * Instantiate this class, or subclass it for easily creating event emitters.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class EventEmitter implements EventEmitterInterface {
+
+ use EventEmitterTrait;
+
+}
diff --git a/vendor/sabre/event/lib/EventEmitterInterface.php b/vendor/sabre/event/lib/EventEmitterInterface.php
new file mode 100644
index 000000000..0e2be2cef
--- /dev/null
+++ b/vendor/sabre/event/lib/EventEmitterInterface.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Sabre\Event;
+
+/**
+ * Event Emitter Interface
+ *
+ * Anything that accepts listeners and emits events should implement this
+ * interface.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+interface EventEmitterInterface {
+
+ /**
+ * Subscribe to an event.
+ *
+ * @param string $eventName
+ * @param callable $callBack
+ * @param int $priority
+ * @return void
+ */
+ function on($eventName, callable $callBack, $priority = 100);
+
+ /**
+ * Subscribe to an event exactly once.
+ *
+ * @param string $eventName
+ * @param callable $callBack
+ * @param int $priority
+ * @return void
+ */
+ function once($eventName, callable $callBack, $priority = 100);
+
+ /**
+ * Emits an event.
+ *
+ * This method will return true if 0 or more listeners were succesfully
+ * handled. false is returned if one of the events broke the event chain.
+ *
+ * If the continueCallBack is specified, this callback will be called every
+ * time before the next event handler is called.
+ *
+ * If the continueCallback returns false, event propagation stops. This
+ * allows you to use the eventEmitter as a means for listeners to implement
+ * functionality in your application, and break the event loop as soon as
+ * some condition is fulfilled.
+ *
+ * Note that returning false from an event subscriber breaks propagation
+ * and returns false, but if the continue-callback stops propagation, this
+ * is still considered a 'successful' operation and returns true.
+ *
+ * Lastly, if there are 5 event handlers for an event. The continueCallback
+ * will be called at most 4 times.
+ *
+ * @param string $eventName
+ * @param array $arguments
+ * @param callback $continueCallBack
+ * @return bool
+ */
+ function emit($eventName, array $arguments = [], callable $continueCallBack = null);
+
+ /**
+ * Returns the list of listeners for an event.
+ *
+ * The list is returned as an array, and the list of events are sorted by
+ * their priority.
+ *
+ * @param string $eventName
+ * @return callable[]
+ */
+ function listeners($eventName);
+
+ /**
+ * Removes a specific listener from an event.
+ *
+ * If the listener could not be found, this method will return false. If it
+ * was removed it will return true.
+ *
+ * @param string $eventName
+ * @param callable $listener
+ * @return bool
+ */
+ function removeListener($eventName, callable $listener);
+
+ /**
+ * Removes all listeners.
+ *
+ * If the eventName argument is specified, all listeners for that event are
+ * removed. If it is not specified, every listener for every event is
+ * removed.
+ *
+ * @param string $eventName
+ * @return void
+ */
+ function removeAllListeners($eventName = null);
+
+}
diff --git a/vendor/sabre/event/lib/EventEmitterTrait.php b/vendor/sabre/event/lib/EventEmitterTrait.php
new file mode 100644
index 000000000..257629fae
--- /dev/null
+++ b/vendor/sabre/event/lib/EventEmitterTrait.php
@@ -0,0 +1,211 @@
+<?php
+
+namespace Sabre\Event;
+
+/**
+ * Event Emitter Trait
+ *
+ * This trait contains all the basic functions to implement an
+ * EventEmitterInterface.
+ *
+ * Using the trait + interface allows you to add EventEmitter capabilities
+ * without having to change your base-class.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+trait EventEmitterTrait {
+
+ /**
+ * The list of listeners
+ *
+ * @var array
+ */
+ protected $listeners = [];
+
+ /**
+ * Subscribe to an event.
+ *
+ * @param string $eventName
+ * @param callable $callBack
+ * @param int $priority
+ * @return void
+ */
+ function on($eventName, callable $callBack, $priority = 100) {
+
+ if (!isset($this->listeners[$eventName])) {
+ $this->listeners[$eventName] = [
+ true, // If there's only one item, it's sorted
+ [$priority],
+ [$callBack]
+ ];
+ } else {
+ $this->listeners[$eventName][0] = false; // marked as unsorted
+ $this->listeners[$eventName][1][] = $priority;
+ $this->listeners[$eventName][2][] = $callBack;
+ }
+
+ }
+
+ /**
+ * Subscribe to an event exactly once.
+ *
+ * @param string $eventName
+ * @param callable $callBack
+ * @param int $priority
+ * @return void
+ */
+ function once($eventName, callable $callBack, $priority = 100) {
+
+ $wrapper = null;
+ $wrapper = function() use ($eventName, $callBack, &$wrapper) {
+
+ $this->removeListener($eventName, $wrapper);
+ return call_user_func_array($callBack, func_get_args());
+
+ };
+
+ $this->on($eventName, $wrapper, $priority);
+
+ }
+
+ /**
+ * Emits an event.
+ *
+ * This method will return true if 0 or more listeners were succesfully
+ * handled. false is returned if one of the events broke the event chain.
+ *
+ * If the continueCallBack is specified, this callback will be called every
+ * time before the next event handler is called.
+ *
+ * If the continueCallback returns false, event propagation stops. This
+ * allows you to use the eventEmitter as a means for listeners to implement
+ * functionality in your application, and break the event loop as soon as
+ * some condition is fulfilled.
+ *
+ * Note that returning false from an event subscriber breaks propagation
+ * and returns false, but if the continue-callback stops propagation, this
+ * is still considered a 'successful' operation and returns true.
+ *
+ * Lastly, if there are 5 event handlers for an event. The continueCallback
+ * will be called at most 4 times.
+ *
+ * @param string $eventName
+ * @param array $arguments
+ * @param callback $continueCallBack
+ * @return bool
+ */
+ function emit($eventName, array $arguments = [], callable $continueCallBack = null) {
+
+ if (is_null($continueCallBack)) {
+
+ foreach ($this->listeners($eventName) as $listener) {
+
+ $result = call_user_func_array($listener, $arguments);
+ if ($result === false) {
+ return false;
+ }
+ }
+
+ } else {
+
+ $listeners = $this->listeners($eventName);
+ $counter = count($listeners);
+
+ foreach ($listeners as $listener) {
+
+ $counter--;
+ $result = call_user_func_array($listener, $arguments);
+ if ($result === false) {
+ return false;
+ }
+
+ if ($counter > 0) {
+ if (!$continueCallBack()) break;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Returns the list of listeners for an event.
+ *
+ * The list is returned as an array, and the list of events are sorted by
+ * their priority.
+ *
+ * @param string $eventName
+ * @return callable[]
+ */
+ function listeners($eventName) {
+
+ if (!isset($this->listeners[$eventName])) {
+ return [];
+ }
+
+ // The list is not sorted
+ if (!$this->listeners[$eventName][0]) {
+
+ // Sorting
+ array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]);
+
+ // Marking the listeners as sorted
+ $this->listeners[$eventName][0] = true;
+ }
+
+ return $this->listeners[$eventName][2];
+
+ }
+
+ /**
+ * Removes a specific listener from an event.
+ *
+ * If the listener could not be found, this method will return false. If it
+ * was removed it will return true.
+ *
+ * @param string $eventName
+ * @param callable $listener
+ * @return bool
+ */
+ function removeListener($eventName, callable $listener) {
+
+ if (!isset($this->listeners[$eventName])) {
+ return false;
+ }
+ foreach ($this->listeners[$eventName][2] as $index => $check) {
+ if ($check === $listener) {
+ unset($this->listeners[$eventName][1][$index]);
+ unset($this->listeners[$eventName][2][$index]);
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Removes all listeners.
+ *
+ * If the eventName argument is specified, all listeners for that event are
+ * removed. If it is not specified, every listener for every event is
+ * removed.
+ *
+ * @param string $eventName
+ * @return void
+ */
+ function removeAllListeners($eventName = null) {
+
+ if (!is_null($eventName)) {
+ unset($this->listeners[$eventName]);
+ } else {
+ $this->listeners = [];
+ }
+
+ }
+
+}
diff --git a/vendor/sabre/event/lib/Loop/Loop.php b/vendor/sabre/event/lib/Loop/Loop.php
new file mode 100644
index 000000000..86ee7c8b0
--- /dev/null
+++ b/vendor/sabre/event/lib/Loop/Loop.php
@@ -0,0 +1,386 @@
+<?php
+
+namespace Sabre\Event\Loop;
+
+/**
+ * A simple eventloop implementation.
+ *
+ * This eventloop supports:
+ * * nextTick
+ * * setTimeout for delayed functions
+ * * setInterval for repeating functions
+ * * stream events using stream_select
+ *
+ * @copyright Copyright (C) 2007-2015 fruux GmbH. (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Loop {
+
+ /**
+ * Executes a function after x seconds.
+ *
+ * @param callable $cb
+ * @param float $timeout timeout in seconds
+ * @return void
+ */
+ function setTimeout(callable $cb, $timeout) {
+
+ $triggerTime = microtime(true) + ($timeout);
+
+ if (!$this->timers) {
+ // Special case when the timers array was empty.
+ $this->timers[] = [$triggerTime, $cb];
+ return;
+ }
+
+ // We need to insert these values in the timers array, but the timers
+ // array must be in reverse-order of trigger times.
+ //
+ // So here we search the array for the insertion point.
+ $index = count($this->timers) - 1;
+ while (true) {
+ if ($triggerTime < $this->timers[$index][0]) {
+ array_splice(
+ $this->timers,
+ $index + 1,
+ 0,
+ [[$triggerTime, $cb]]
+ );
+ break;
+ } elseif ($index === 0) {
+ array_unshift($this->timers, [$triggerTime, $cb]);
+ break;
+ }
+ $index--;
+
+ }
+
+ }
+
+ /**
+ * Executes a function every x seconds.
+ *
+ * The value this function returns can be used to stop the interval with
+ * clearInterval.
+ *
+ * @param callable $cb
+ * @param float $timeout
+ * @return array
+ */
+ function setInterval(callable $cb, $timeout) {
+
+ $keepGoing = true;
+ $f = null;
+
+ $f = function() use ($cb, &$f, $timeout, &$keepGoing) {
+ if ($keepGoing) {
+ $cb();
+ $this->setTimeout($f, $timeout);
+ }
+ };
+ $this->setTimeout($f, $timeout);
+
+ // Really the only thing that matters is returning the $keepGoing
+ // boolean value.
+ //
+ // We need to pack it in an array to allow returning by reference.
+ // Because I'm worried people will be confused by using a boolean as a
+ // sort of identifier, I added an extra string.
+ return ['I\'m an implementation detail', &$keepGoing];
+
+ }
+
+ /**
+ * Stops a running internval.
+ *
+ * @param array $intervalId
+ * @return void
+ */
+ function clearInterval($intervalId) {
+
+ $intervalId[1] = false;
+
+ }
+
+ /**
+ * Runs a function immediately at the next iteration of the loop.
+ *
+ * @param callable $cb
+ * @return void
+ */
+ function nextTick(callable $cb) {
+
+ $this->nextTick[] = $cb;
+
+ }
+
+
+ /**
+ * Adds a read stream.
+ *
+ * The callback will be called as soon as there is something to read from
+ * the stream.
+ *
+ * You MUST call removeReadStream after you are done with the stream, to
+ * prevent the eventloop from never stopping.
+ *
+ * @param resource $stream
+ * @param callable $cb
+ * @return void
+ */
+ function addReadStream($stream, callable $cb) {
+
+ $this->readStreams[(int)$stream] = $stream;
+ $this->readCallbacks[(int)$stream] = $cb;
+
+ }
+
+ /**
+ * Adds a write stream.
+ *
+ * The callback will be called as soon as the system reports it's ready to
+ * receive writes on the stream.
+ *
+ * You MUST call removeWriteStream after you are done with the stream, to
+ * prevent the eventloop from never stopping.
+ *
+ * @param resource $stream
+ * @param callable $cb
+ * @return void
+ */
+ function addWriteStream($stream, callable $cb) {
+
+ $this->writeStreams[(int)$stream] = $stream;
+ $this->writeCallbacks[(int)$stream] = $cb;
+
+ }
+
+ /**
+ * Stop watching a stream for reads.
+ *
+ * @param resource $stream
+ * @return void
+ */
+ function removeReadStream($stream) {
+
+ unset(
+ $this->readStreams[(int)$stream],
+ $this->readCallbacks[(int)$stream]
+ );
+
+ }
+
+ /**
+ * Stop watching a stream for writes.
+ *
+ * @param resource $stream
+ * @return void
+ */
+ function removeWriteStream($stream) {
+
+ unset(
+ $this->writeStreams[(int)$stream],
+ $this->writeCallbacks[(int)$stream]
+ );
+
+ }
+
+
+ /**
+ * Runs the loop.
+ *
+ * This function will run continiously, until there's no more events to
+ * handle.
+ *
+ * @return void
+ */
+ function run() {
+
+ $this->running = true;
+
+ do {
+
+ $hasEvents = $this->tick(true);
+
+ } while ($this->running && $hasEvents);
+ $this->running = false;
+
+ }
+
+ /**
+ * Executes all pending events.
+ *
+ * If $block is turned true, this function will block until any event is
+ * triggered.
+ *
+ * If there are now timeouts, nextTick callbacks or events in the loop at
+ * all, this function will exit immediately.
+ *
+ * This function will return true if there are _any_ events left in the
+ * loop after the tick.
+ *
+ * @param bool $block
+ * @return bool
+ */
+ function tick($block = false) {
+
+ $this->runNextTicks();
+ $nextTimeout = $this->runTimers();
+
+ // Calculating how long runStreams should at most wait.
+ if (!$block) {
+ // Don't wait
+ $streamWait = 0;
+ } elseif ($this->nextTick) {
+ // There's a pending 'nextTick'. Don't wait.
+ $streamWait = 0;
+ } elseif (is_numeric($nextTimeout)) {
+ // Wait until the next Timeout should trigger.
+ $streamWait = $nextTimeout;
+ } else {
+ // Wait indefinitely
+ $streamWait = null;
+ }
+
+ $this->runStreams($streamWait);
+
+ return ($this->readStreams || $this->writeStreams || $this->nextTick || $this->timers);
+
+ }
+
+ /**
+ * Stops a running eventloop
+ *
+ * @return void
+ */
+ function stop() {
+
+ $this->running = false;
+
+ }
+
+ /**
+ * Executes all 'nextTick' callbacks.
+ *
+ * return void
+ */
+ protected function runNextTicks() {
+
+ $nextTick = $this->nextTick;
+ $this->nextTick = [];
+
+ foreach ($nextTick as $cb) {
+ $cb();
+ }
+
+ }
+
+ /**
+ * Runs all pending timers.
+ *
+ * After running the timer callbacks, this function returns the number of
+ * seconds until the next timer should be executed.
+ *
+ * If there's no more pending timers, this function returns null.
+ *
+ * @return float
+ */
+ protected function runTimers() {
+
+ $now = microtime(true);
+ while (($timer = array_pop($this->timers)) && $timer[0] < $now) {
+ $timer[1]();
+ }
+ // Add the last timer back to the array.
+ if ($timer) {
+ $this->timers[] = $timer;
+ return $timer[0] - microtime(true);
+ }
+
+ }
+
+ /**
+ * Runs all pending stream events.
+ *
+ * @param float $timeout
+ */
+ protected function runStreams($timeout) {
+
+ if ($this->readStreams || $this->writeStreams) {
+
+ $read = $this->readStreams;
+ $write = $this->writeStreams;
+ $except = null;
+ if (stream_select($read, $write, $except, null, $timeout)) {
+
+ // See PHP Bug https://bugs.php.net/bug.php?id=62452
+ // Fixed in PHP7
+ foreach ($read as $readStream) {
+ $readCb = $this->readCallbacks[(int)$readStream];
+ $readCb();
+ }
+ foreach ($write as $writeStream) {
+ $writeCb = $this->writeCallbacks[(int)$writeStream];
+ $writeCb();
+ }
+
+ }
+
+ } elseif ($this->running && ($this->nextTick || $this->timers)) {
+ usleep($timeout !== null ? $timeout * 1000000 : 200000);
+ }
+
+ }
+
+ /**
+ * Is the main loop active
+ *
+ * @var bool
+ */
+ protected $running = false;
+
+ /**
+ * A list of timers, added by setTimeout.
+ *
+ * @var array
+ */
+ protected $timers = [];
+
+ /**
+ * A list of 'nextTick' callbacks.
+ *
+ * @var callable[]
+ */
+ protected $nextTick = [];
+
+ /**
+ * List of readable streams for stream_select, indexed by stream id.
+ *
+ * @var resource[]
+ */
+ protected $readStreams = [];
+
+ /**
+ * List of writable streams for stream_select, indexed by stream id.
+ *
+ * @var resource[]
+ */
+ protected $writeStreams = [];
+
+ /**
+ * List of read callbacks, indexed by stream id.
+ *
+ * @var callback[]
+ */
+ protected $readCallbacks = [];
+
+ /**
+ * List of write callbacks, indexed by stream id.
+ *
+ * @var callback[]
+ */
+ protected $writeCallbacks = [];
+
+
+}
diff --git a/vendor/sabre/event/lib/Loop/functions.php b/vendor/sabre/event/lib/Loop/functions.php
new file mode 100644
index 000000000..56c5bc8c7
--- /dev/null
+++ b/vendor/sabre/event/lib/Loop/functions.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace Sabre\Event\Loop;
+
+/**
+ * Executes a function after x seconds.
+ *
+ * @param callable $cb
+ * @param float $timeout timeout in seconds
+ * @return void
+ */
+function setTimeout(callable $cb, $timeout) {
+
+ instance()->setTimeout($cb, $timeout);
+
+}
+
+/**
+ * Executes a function every x seconds.
+ *
+ * The value this function returns can be used to stop the interval with
+ * clearInterval.
+ *
+ * @param callable $cb
+ * @param float $timeout
+ * @return array
+ */
+function setInterval(callable $cb, $timeout) {
+
+ return instance()->setInterval($cb, $timeout);
+
+}
+
+/**
+ * Stops a running internval.
+ *
+ * @param array $intervalId
+ * @return void
+ */
+function clearInterval($intervalId) {
+
+ instance()->clearInterval($intervalId);
+
+}
+
+/**
+ * Runs a function immediately at the next iteration of the loop.
+ *
+ * @param callable $cb
+ * @return void
+ */
+function nextTick(callable $cb) {
+
+ instance()->nextTick($cb);
+
+}
+
+
+/**
+ * Adds a read stream.
+ *
+ * The callback will be called as soon as there is something to read from
+ * the stream.
+ *
+ * You MUST call removeReadStream after you are done with the stream, to
+ * prevent the eventloop from never stopping.
+ *
+ * @param resource $stream
+ * @param callable $cb
+ * @return void
+ */
+function addReadStream($stream, callable $cb) {
+
+ instance()->addReadStream($stream, $cb);
+
+}
+
+/**
+ * Adds a write stream.
+ *
+ * The callback will be called as soon as the system reports it's ready to
+ * receive writes on the stream.
+ *
+ * You MUST call removeWriteStream after you are done with the stream, to
+ * prevent the eventloop from never stopping.
+ *
+ * @param resource $stream
+ * @param callable $cb
+ * @return void
+ */
+function addWriteStream($stream, callable $cb) {
+
+ instance()->addWriteStream($stream, $cb);
+
+}
+
+/**
+ * Stop watching a stream for reads.
+ *
+ * @param resource $stream
+ * @return void
+ */
+function removeReadStream($stream) {
+
+ instance()->removeReadStream($stream);
+
+}
+
+/**
+ * Stop watching a stream for writes.
+ *
+ * @param resource $stream
+ * @return void
+ */
+function removeWriteStream($stream) {
+
+ instance()->removeWriteStream($stream);
+
+}
+
+
+/**
+ * Runs the loop.
+ *
+ * This function will run continiously, until there's no more events to
+ * handle.
+ *
+ * @return void
+ */
+function run() {
+
+ instance()->run();
+
+}
+
+/**
+ * Executes all pending events.
+ *
+ * If $block is turned true, this function will block until any event is
+ * triggered.
+ *
+ * If there are now timeouts, nextTick callbacks or events in the loop at
+ * all, this function will exit immediately.
+ *
+ * This function will return true if there are _any_ events left in the
+ * loop after the tick.
+ *
+ * @param bool $block
+ * @return bool
+ */
+function tick($block = false) {
+
+ return instance()->tick($block);
+
+}
+
+/**
+ * Stops a running eventloop
+ *
+ * @return void
+ */
+function stop() {
+
+ instance()->stop();
+
+}
+
+/**
+ * Retrieves or sets the global Loop object.
+ *
+ * @param Loop $newLoop
+ */
+function instance(Loop $newLoop = null) {
+
+ static $loop;
+ if ($newLoop) {
+ $loop = $newLoop;
+ } elseif (!$loop) {
+ $loop = new Loop();
+ }
+ return $loop;
+
+}
diff --git a/vendor/sabre/event/lib/Promise.php b/vendor/sabre/event/lib/Promise.php
new file mode 100644
index 000000000..1c874c1bd
--- /dev/null
+++ b/vendor/sabre/event/lib/Promise.php
@@ -0,0 +1,320 @@
+<?php
+
+namespace Sabre\Event;
+
+use Exception;
+
+/**
+ * An implementation of the Promise pattern.
+ *
+ * A promise represents the result of an asynchronous operation.
+ * At any given point a promise can be in one of three states:
+ *
+ * 1. Pending (the promise does not have a result yet).
+ * 2. Fulfilled (the asynchronous operation has completed with a result).
+ * 3. Rejected (the asynchronous operation has completed with an error).
+ *
+ * To get a callback when the operation has finished, use the `then` method.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Promise {
+
+ /**
+ * The asynchronous operation is pending.
+ */
+ const PENDING = 0;
+
+ /**
+ * The asynchronous operation has completed, and has a result.
+ */
+ const FULFILLED = 1;
+
+ /**
+ * The asynchronous operation has completed with an error.
+ */
+ const REJECTED = 2;
+
+ /**
+ * The current state of this promise.
+ *
+ * @var int
+ */
+ public $state = self::PENDING;
+
+ /**
+ * Creates the promise.
+ *
+ * The passed argument is the executor. The executor is automatically
+ * called with two arguments.
+ *
+ * Each are callbacks that map to $this->fulfill and $this->reject.
+ * Using the executor is optional.
+ *
+ * @param callable $executor
+ */
+ function __construct(callable $executor = null) {
+
+ if ($executor) {
+ $executor(
+ [$this, 'fulfill'],
+ [$this, 'reject']
+ );
+ }
+
+ }
+
+ /**
+ * This method allows you to specify the callback that will be called after
+ * the promise has been fulfilled or rejected.
+ *
+ * Both arguments are optional.
+ *
+ * This method returns a new promise, which can be used for chaining.
+ * If either the onFulfilled or onRejected callback is called, you may
+ * return a result from this callback.
+ *
+ * If the result of this callback is yet another promise, the result of
+ * _that_ promise will be used to set the result of the returned promise.
+ *
+ * If either of the callbacks return any other value, the returned promise
+ * is automatically fulfilled with that value.
+ *
+ * If either of the callbacks throw an exception, the returned promise will
+ * be rejected and the exception will be passed back.
+ *
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ * @return Promise
+ */
+ function then(callable $onFulfilled = null, callable $onRejected = null) {
+
+ // This new subPromise will be returned from this function, and will
+ // be fulfilled with the result of the onFulfilled or onRejected event
+ // handlers.
+ $subPromise = new self();
+
+ switch ($this->state) {
+ case self::PENDING :
+ // The operation is pending, so we keep a reference to the
+ // event handlers so we can call them later.
+ $this->subscribers[] = [$subPromise, $onFulfilled, $onRejected];
+ break;
+ case self::FULFILLED :
+ // The async operation is already fulfilled, so we trigger the
+ // onFulfilled callback asap.
+ $this->invokeCallback($subPromise, $onFulfilled);
+ break;
+ case self::REJECTED :
+ // The async operation failed, so we call teh onRejected
+ // callback asap.
+ $this->invokeCallback($subPromise, $onRejected);
+ break;
+ }
+ return $subPromise;
+
+ }
+
+ /**
+ * Add a callback for when this promise is rejected.
+ *
+ * Its usage is identical to then(). However, the otherwise() function is
+ * preferred.
+ *
+ * @param callable $onRejected
+ * @return Promise
+ */
+ function otherwise(callable $onRejected) {
+
+ return $this->then(null, $onRejected);
+
+ }
+
+ /**
+ * Marks this promise as fulfilled and sets its return value.
+ *
+ * @param mixed $value
+ * @return void
+ */
+ function fulfill($value = null) {
+ if ($this->state !== self::PENDING) {
+ throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
+ }
+ $this->state = self::FULFILLED;
+ $this->value = $value;
+ foreach ($this->subscribers as $subscriber) {
+ $this->invokeCallback($subscriber[0], $subscriber[1]);
+ }
+ }
+
+ /**
+ * Marks this promise as rejected, and set it's rejection reason.
+ *
+ * While it's possible to use any PHP value as the reason, it's highly
+ * recommended to use an Exception for this.
+ *
+ * @param mixed $reason
+ * @return void
+ */
+ function reject($reason = null) {
+ if ($this->state !== self::PENDING) {
+ throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
+ }
+ $this->state = self::REJECTED;
+ $this->value = $reason;
+ foreach ($this->subscribers as $subscriber) {
+ $this->invokeCallback($subscriber[0], $subscriber[2]);
+ }
+
+ }
+
+ /**
+ * Stops execution until this promise is resolved.
+ *
+ * This method stops exection completely. If the promise is successful with
+ * a value, this method will return this value. If the promise was
+ * rejected, this method will throw an exception.
+ *
+ * This effectively turns the asynchronous operation into a synchronous
+ * one. In PHP it might be useful to call this on the last promise in a
+ * chain.
+ *
+ * @throws Exception
+ * @return mixed
+ */
+ function wait() {
+
+ $hasEvents = true;
+ while ($this->state === self::PENDING) {
+
+ if (!$hasEvents) {
+ throw new \LogicException('There were no more events in the loop. This promise will never be fulfilled.');
+ }
+
+ // As long as the promise is not fulfilled, we tell the event loop
+ // to handle events, and to block.
+ $hasEvents = Loop\tick(true);
+
+ }
+
+ if ($this->state === self::FULFILLED) {
+ // If the state of this promise is fulfilled, we can return the value.
+ return $this->value;
+ } else {
+ // If we got here, it means that the asynchronous operation
+ // errored. Therefore we need to throw an exception.
+ $reason = $this->value;
+ if ($reason instanceof Exception) {
+ throw $reason;
+ } elseif (is_scalar($reason)) {
+ throw new Exception($reason);
+ } else {
+ $type = is_object($reason) ? get_class($reason) : gettype($reason);
+ throw new Exception('Promise was rejected with reason of type: ' . $type);
+ }
+ }
+
+
+ }
+
+
+ /**
+ * A list of subscribers. Subscribers are the callbacks that want us to let
+ * them know if the callback was fulfilled or rejected.
+ *
+ * @var array
+ */
+ protected $subscribers = [];
+
+ /**
+ * The result of the promise.
+ *
+ * If the promise was fulfilled, this will be the result value. If the
+ * promise was rejected, this property hold the rejection reason.
+ *
+ * @var mixed
+ */
+ protected $value = null;
+
+ /**
+ * This method is used to call either an onFulfilled or onRejected callback.
+ *
+ * This method makes sure that the result of these callbacks are handled
+ * correctly, and any chained promises are also correctly fulfilled or
+ * rejected.
+ *
+ * @param Promise $subPromise
+ * @param callable $callBack
+ * @return void
+ */
+ private function invokeCallback(Promise $subPromise, callable $callBack = null) {
+
+ // We use 'nextTick' to ensure that the event handlers are always
+ // triggered outside of the calling stack in which they were originally
+ // passed to 'then'.
+ //
+ // This makes the order of execution more predictable.
+ Loop\nextTick(function() use ($callBack, $subPromise) {
+ if (is_callable($callBack)) {
+ try {
+
+ $result = $callBack($this->value);
+ if ($result instanceof self) {
+ // If the callback (onRejected or onFulfilled)
+ // returned a promise, we only fulfill or reject the
+ // chained promise once that promise has also been
+ // resolved.
+ $result->then([$subPromise, 'fulfill'], [$subPromise, 'reject']);
+ } else {
+ // If the callback returned any other value, we
+ // immediately fulfill the chained promise.
+ $subPromise->fulfill($result);
+ }
+ } catch (Exception $e) {
+ // If the event handler threw an exception, we need to make sure that
+ // the chained promise is rejected as well.
+ $subPromise->reject($e);
+ }
+ } else {
+ if ($this->state === self::FULFILLED) {
+ $subPromise->fulfill($this->value);
+ } else {
+ $subPromise->reject($this->value);
+ }
+ }
+ });
+ }
+
+ /**
+ * Alias for 'otherwise'.
+ *
+ * This function is now deprecated and will be removed in a future version.
+ *
+ * @param callable $onRejected
+ * @deprecated
+ * @return Promise
+ */
+ function error(callable $onRejected) {
+
+ return $this->otherwise($onRejected);
+
+ }
+
+ /**
+ * Deprecated.
+ *
+ * Please use Sabre\Event\Promise::all
+ *
+ * @param Promise[] $promises
+ * @deprecated
+ * @return Promise
+ */
+ static function all(array $promises) {
+
+ return Promise\all($promises);
+
+ }
+
+}
diff --git a/vendor/sabre/event/lib/Promise/functions.php b/vendor/sabre/event/lib/Promise/functions.php
new file mode 100644
index 000000000..3604b8aaa
--- /dev/null
+++ b/vendor/sabre/event/lib/Promise/functions.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Sabre\Event\Promise;
+
+use Sabre\Event\Promise;
+
+/**
+ * This file contains a set of functions that are useful for dealing with the
+ * Promise object.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+
+
+/**
+ * This function takes an array of Promises, and returns a Promise that
+ * resolves when all of the given arguments have resolved.
+ *
+ * The returned Promise will resolve with a value that's an array of all the
+ * values the given promises have been resolved with.
+ *
+ * This array will be in the exact same order as the array of input promises.
+ *
+ * If any of the given Promises fails, the returned promise will immidiately
+ * fail with the first Promise that fails, and its reason.
+ *
+ * @param Promise[] $promises
+ * @return Promise
+ */
+function all(array $promises) {
+
+ return new Promise(function($success, $fail) use ($promises) {
+
+ $successCount = 0;
+ $completeResult = [];
+
+ foreach ($promises as $promiseIndex => $subPromise) {
+
+ $subPromise->then(
+ function($result) use ($promiseIndex, &$completeResult, &$successCount, $success, $promises) {
+ $completeResult[$promiseIndex] = $result;
+ $successCount++;
+ if ($successCount === count($promises)) {
+ $success($completeResult);
+ }
+ return $result;
+ }
+ )->error(
+ function($reason) use ($fail) {
+ $fail($reason);
+ }
+ );
+
+ }
+ });
+
+}
+
+/**
+ * The race function returns a promise that resolves or rejects as soon as
+ * one of the promises in the argument resolves or rejects.
+ *
+ * The returned promise will resolve or reject with the value or reason of
+ * that first promise.
+ *
+ * @param Promise[] $promises
+ * @return Promise
+ */
+function race(array $promises) {
+
+ return new Promise(function($success, $fail) use ($promises) {
+
+ $alreadyDone = false;
+ foreach ($promises as $promise) {
+
+ $promise->then(
+ function($result) use ($success, &$alreadyDone) {
+ if ($alreadyDone) {
+ return;
+ }
+ $alreadyDone = true;
+ $success($result);
+ },
+ function($reason) use ($fail, &$alreadyDone) {
+ if ($alreadyDone) {
+ return;
+ }
+ $alreadyDone = true;
+ $fail($reason);
+ }
+ );
+
+ }
+
+ });
+
+}
+
+
+/**
+ * Returns a Promise that resolves with the given value.
+ *
+ * If the value is a promise, the returned promise will attach itself to that
+ * promise and eventually get the same state as the followed promise.
+ *
+ * @param mixed $value
+ * @return Promise
+ */
+function resolve($value) {
+
+ if ($value instanceof Promise) {
+ return $value->then();
+ } else {
+ $promise = new Promise();
+ $promise->fulfill($value);
+ return $promise;
+ }
+
+}
+
+/**
+ * Returns a Promise that will reject with the given reason.
+ *
+ * @param mixed $reason
+ * @return Promise
+ */
+function reject($reason) {
+
+ $promise = new Promise();
+ $promise->reject($reason);
+ return $promise;
+
+}
diff --git a/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php b/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php
new file mode 100644
index 000000000..86a6c5b3f
--- /dev/null
+++ b/vendor/sabre/event/lib/PromiseAlreadyResolvedException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Sabre\Event;
+
+/**
+ * This exception is thrown when the user tried to reject or fulfill a promise,
+ * after either of these actions were already performed.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class PromiseAlreadyResolvedException extends \LogicException {
+
+}
diff --git a/vendor/sabre/event/lib/Version.php b/vendor/sabre/event/lib/Version.php
new file mode 100644
index 000000000..5de22193f
--- /dev/null
+++ b/vendor/sabre/event/lib/Version.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Sabre\Event;
+
+/**
+ * This class contains the version number for this package.
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Version {
+
+ /**
+ * Full version number
+ */
+ const VERSION = '3.0.0';
+
+}
diff --git a/vendor/sabre/event/lib/coroutine.php b/vendor/sabre/event/lib/coroutine.php
new file mode 100644
index 000000000..19c0ba8a7
--- /dev/null
+++ b/vendor/sabre/event/lib/coroutine.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Sabre\Event;
+
+use Generator;
+use Exception;
+
+/**
+ * Turn asynchronous promise-based code into something that looks synchronous
+ * again, through the use of generators.
+ *
+ * Example without coroutines:
+ *
+ * $promise = $httpClient->request('GET', '/foo');
+ * $promise->then(function($value) {
+ *
+ * return $httpClient->request('DELETE','/foo');
+ *
+ * })->then(function($value) {
+ *
+ * return $httpClient->request('PUT', '/foo');
+ *
+ * })->error(function($reason) {
+ *
+ * echo "Failed because: $reason\n";
+ *
+ * });
+ *
+ * Example with coroutines:
+ *
+ * coroutine(function() {
+ *
+ * try {
+ * yield $httpClient->request('GET', '/foo');
+ * yield $httpClient->request('DELETE', /foo');
+ * yield $httpClient->request('PUT', '/foo');
+ * } catch(\Exception $reason) {
+ * echo "Failed because: $reason\n";
+ * }
+ *
+ * });
+ *
+ * @copyright Copyright (C) 2013-2015 fruux GmbH. All rights reserved.
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+function coroutine(callable $gen) {
+
+ $generator = $gen();
+ if (!$generator instanceof Generator) {
+ throw new \InvalidArgumentException('You must pass a generator function');
+ }
+
+ // This is the value we're returning.
+ $promise = new Promise();
+
+ $lastYieldResult = null;
+
+ /**
+ * So tempted to use the mythical y-combinator here, but it's not needed in
+ * PHP.
+ */
+ $advanceGenerator = function() use (&$advanceGenerator, $generator, $promise, &$lastYieldResult) {
+
+ while ($generator->valid()) {
+
+ $yieldedValue = $generator->current();
+ if ($yieldedValue instanceof Promise) {
+ $yieldedValue->then(
+ function($value) use ($generator, &$advanceGenerator, &$lastYieldResult) {
+ $lastYieldResult = $value;
+ $generator->send($value);
+ $advanceGenerator();
+ },
+ function($reason) use ($generator, $advanceGenerator) {
+ if ($reason instanceof Exception) {
+ $generator->throw($reason);
+ } elseif (is_scalar($reason)) {
+ $generator->throw(new Exception($reason));
+ } else {
+ $type = is_object($reason) ? get_class($reason) : gettype($reason);
+ $generator->throw(new Exception('Promise was rejected with reason of type: ' . $type));
+ }
+ $advanceGenerator();
+ }
+ )->error(function($reason) use ($promise) {
+ // This error handler would be called, if something in the
+ // generator throws an exception, and it's not caught
+ // locally.
+ $promise->reject($reason);
+ });
+ // We need to break out of the loop, because $advanceGenerator
+ // will be called asynchronously when the promise has a result.
+ break;
+ } else {
+ // If the value was not a promise, we'll just let it pass through.
+ $lastYieldResult = $yieldedValue;
+ $generator->send($yieldedValue);
+ }
+
+ }
+
+ // If the generator is at the end, and we didn't run into an exception,
+ // we can fullfill the promise with the last thing that was yielded to
+ // us.
+ if (!$generator->valid() && $promise->state === Promise::PENDING) {
+ $promise->fulfill($lastYieldResult);
+ }
+
+ };
+
+ try {
+ $advanceGenerator();
+ } catch (Exception $e) {
+ $promise->reject($e);
+ }
+
+ return $promise;
+
+}