Commits

Thomas Weinert committed 6aa63ef

Comments (0)

Files changed (102)

 Carica Io
 =========
 
-License:   [The MIT License](http://www.opensource.org/licenses/mit-license.php)
-           
-Copyright: 2013 Thomas Weinert <thomas@weinert.info>
- 
-Carica Io is a collection of experimental php classes and scripts
-for non-blocking I/O.
-
-***It's a learning project not a product. Use it at your own risk.***
-
-Basics
-------
-
-The repository provides the API needed for non-blocking I/O. A
-simple event loop and event emitter are included. The loop 
-implementation is not performance optimized, yet.
-
-Firmata
--------
-
-Originally a Firmata client library was part of this project. It is now an
-separate project called [Carica Firmata](https://bitbucket.org/ThomasWeinert/carica-firmata)
+Moved to https://github.com/ThomasWeinert/carica-io

composer.json

-{
-  "name": "carica/io",
-  "type": "library",
-  "description": "Non blocking I/O for PHP",
-  "keywords": ["non-blocking-io", "asynchronous-io"],
-  "homepage": "https://bitbucket.org/ThomasWeinert/carica-io/",
-  "license": "MIT",
-  "authors": [
-    {"name": "Thomas Weinert", "email": "thomas@weinert.info"}
-  ],
-  "require": {
-    "php": ">=5.4"
-  },
-  "autoload": {
-    "psr-4": {
-      "Carica\\Io\\": "src\\"
-    }
-  }
-}

example/Http/ajax/ajax.php

-<?php
-include(__DIR__.'/../../../vendor/autoload.php');
-
-use Carica\Io\Network\Http;
-
-$route = new Http\Route();
-$route->match(
-  '/time',
-  function (Http\Request $request) {
-    $response = $request->createResponse();
-    $response->content = new Http\Response\Content\Xml();
-    $dom = $response->content->document;
-    $dom->appendChild($rootNode = $dom->createElement('time'));
-    $rootNode->appendChild($dom->createTextNode(date('Y-m-d H:i:s')));
-    return $response;
-  }
-);
-$route->match(
-  '/',
-  function (Http\Request $request) {
-    $response = $request->createResponse();
-    $response->content = new Http\Response\Content\File(
-      __DIR__.'/index.html', 'text/html', 'utf-8'
-    );
-    return $response;
-  }
-);
-
-$server = new Carica\Io\Network\Http\Server($route);
-$server->listen(8080);
-
-$loop = Carica\Io\Event\Loop\Factory::get();
-$loop->setInterval(
-  function() use ($loop) {
-    echo "Current event count: ", $loop->count(), "\n";
-    gc_collect_cycles();
-  },
-  5000
-);
-
-Carica\Io\Event\Loop\Factory::run();

example/Http/ajax/index.html

-<!DOCTYPE html>
-<html>
-  <head>
-    <title>Ajax Time</title>
-  </head>
-  <body>
-    <div id="ajaxResult"></div>
-    <script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
-    <script type="text/javascript">
-      jQuery(
-        function () {
-          window.setInterval(
-            function () {
-              jQuery
-                .ajax(
-                  {
-                    url : 'time',
-                    cache : false
-                  }
-                )
-                .done(
-                  function(response) {
-                    jQuery('#ajaxResult').text(jQuery(response).text()); 
-                  }  
-                );
-            },
-            1000
-          );
-        }  
-      );
-    </script>
-  </body>
-</html>

example/Http/files/hello.html

-<!DOCTYPE html!>
-<html>
-  <head>
-    <title>Hello World</title>
-  </head>
-  <body>
-    Hello World!
-  </body>
-</html>

example/Http/hello-world.php

-<?php
-include(__DIR__.'/../../vendor/autoload.php');
-
-use Carica\Io\Network\Http;
-
-$server = new Carica\Io\Network\Server();
-$server->events()->on(
-  'connection',
-  function ($stream) {
-    $request = new Http\Connection($stream);
-    $request->events()->on(
-      'request',
-      function (Http\Request $request) {
-        echo $request->method.' '.$request->url."\n";
-        $request->connection()->write(
-          "HTTP/1.1 200 OK\r\n".
-          "Connection: close\r\n".
-          "Content-Length: 11\r\n".
-          "Content-Type: text/plain; charset=UTF-8\r\n\r\n".
-          "Hallo Welt!"
-        );
-        $request->connection()->close();
-      }
-    );
-  }
-);
-
-$server->listen(8080);
-
-Carica\Io\Event\Loop\Factory::run();

example/Http/route.php

-<?php
-include(__DIR__.'/../../vendor/autoload.php');
-
-use Carica\Io\Network\Http;
-
-$route = new Carica\Io\Network\Http\Route();
-$route->match(
-  '/hello/{name}',
-  function (Http\Request $request, $parameters) {
-    $response = $request->createResponse(
-      new Http\Response\Content\String(
-        "Hello ".$parameters['name']."!\n"
-      )
-    );
-    return $response;
-  }
-);
-$route->match(
-  '/agent',
-  function (Http\Request $request) {
-    $response = $request->createResponse(
-      new Http\Response\Content\String(
-        $request->headers['User-Agent']
-      )
-    );
-    return $response;
-  }
-);
-$route->match(
-  '/xml',
-  function (Http\Request $request) {
-    $response = $request->createResponse(new Http\Response\Content\Xml());
-    $dom = $response->content->document;
-    $dom->appendChild($root = $dom->createElement('response'));
-    foreach ($request->query as $name => $value) {
-      $root->appendChild($parameter = $dom->createElement('query-parameter'));
-      $parameter->setAttribute('name', $name);
-      if (NULL !== $value) {
-        $parameter->appendChild($dom->createTextNode($value));
-      }
-    }
-    return $response;
-  }
-);
-$route->match('/hello', new Http\Route\File(__DIR__.'/files/hello.html'));
-$route->startsWith('/files', new Http\Route\Directory(__DIR__));
-
-$server = new Carica\Io\Network\Http\Server($route);
-$server->listen(8080);
-
-Carica\Io\Event\Loop\Factory::run();

example/MySQL/parallel.php

-<?php
-include(__DIR__.'/../../vendor/autoload.php');
-
-use Carica\Io;
-
-$mysqlOne = new Io\Deferred\MySQL(new mysqli('localhost'));
-$mysqlTwo = new Io\Deferred\MySQL(new mysqli('localhost'));
-$time = microtime(TRUE);
-$debug = function($result) use ($time) {
-  var_dump(iterator_to_array($result));
-  var_dump(microtime(TRUE) - $time);
-};
-$queries = Io\Deferred::When(
-  $mysqlOne("SELECT 'Query 1', SLEEP(5)")
-    ->done($debug),
-  $mysqlTwo("SELECT 'Query 2', SLEEP(1)")
-    ->done($debug)
-);
-Io\Event\Loop\Factory::run($queries);
-
-

example/Serial/monitor.php

-<?php
-include(__DIR__.'/../../vendor/autoload.php');
-
-use Carica\Io;
-
-$port = 'COM9:';
-$baud = 57000;
-
-Io\Stream\Serial\Factory::useDio(FALSE);
-$serial = Io\Stream\Serial\Factory::create($port, $baud);
-
-$serial
-  ->events()
-  ->on(
-    'read-data',
-    function ($data) {
-      echo $data;
-    }
-  );
-$serial->open();
-
-Io\Event\Loop\Factory::run();

example/chat.php

-<?php
-/**
- * A really simple chat server. Clients can connect to it using netcat
- *
- * Basically a php implementation of
- * http://dhotson.tumblr.com/post/271733389/a-simple-chat-server-in-node-js
- */
-
-include(__DIR__.'/../vendor/autoload.php');
-
-class Client {
-
-  /**
-   * @var Carica\Io\Stream
-   */
-  public $connection = NULL;
-  /**
-   * @var string
-   */
-  public $name = NULL;
-}
-
-function broadcast($clients, $data) {
-  foreach ($clients as $recipient) {
-    if ($recipient->connection->isActive()) {
-      $recipient->connection->write($data);
-    }
-  }
-}
-
-use Carica\Io;
-
-$clients = array();
-
-$server = new Io\Network\Server();
-$server->events()->on(
-  'connection',
-  function ($stream) use (&$clients) {
-    echo "Client connected: $stream\n";
-    $client = new Client();
-    $client->connection = new Io\Network\Connection($stream);
-    $client->connection->write("Welcome, enter your username:\n");
-    $client->connection->events()->on(
-      'read-data',
-      function($data) use ($client, &$clients) {
-        if (empty($client->name) &&
-            preg_match('(\S+)', $data, $matches) &&
-            !isset($clients[$matches[0]])) {
-          $client->name = $matches[0];
-          $clients[$client->name] = $client;
-          $client->connection->write(str_repeat('=', 72)."\n");
-          broadcast($clients, $client->name." has joined.\n");
-          echo $client->name." has joined.\n";
-          return;
-        }
-        if (!empty($client->name)) {
-          if (preg_match('(^/(?P<command>.*))', $data, $matches)) {
-            switch ($matches['command']) {
-            case 'users' :
-              foreach ($clients as $user) {
-                $client->connection->write('- '.$user->name."\n");
-              }
-              break;
-            case 'quit' :
-              $client->connection->close();
-              break;
-            default :
-              $client->connection->write("Unknown command.\n");
-            }
-            return;
-          }
-          broadcast($clients, $client->name.': '.$data);
-        }
-      }
-    );
-
-    $client->connection->events()->once(
-      'close',
-      function () use ($client, &$clients) {
-        unset($clients[$client->name]);
-        broadcast($clients, $client->name." has left\n");
-        echo $client->name." has left.\n";
-      }
-    );
-  }
-);
-
-$server->listen(7000);
-Io\Event\Loop\Factory::run();

example/loop.php

-<?php
-include(__DIR__.'/../vendor/autoload.php');
-
-use Carica\Io\Event\Loop;
-
-$loop = Loop\Factory::get();
-
-$i = 0;
-
-$loop->setInterval(
-  function () use (&$i) {
-    echo $i++;
-  },
-  1000
-);
-$loop->setTimeout(
-  function () use ($loop) {
-    $loop->stop();
-  },
-  10000
-);
-
-$loop->run();

example/stream-read.php

-<?php
-include(__DIR__.'/../vendor/autoload.php');
-
-use Carica\Io\Event\Loop;
-use Carica\Io\Stream;
-
-$loop = Loop\Factory::get();
-$write = fopen('c:/tmp/sample.txt', 'w');
-
-$stream = new Stream\File('c:/tmp/sample.txt');
-$stream->events()->on(
-  'read-data',
-  function($data) {
-    echo $data;
-  }
-);
-$stream->events()->on(
-  'error',
-  function($error) use ($loop) {
-    echo $error;
-    $loop->stop();
-  }
-);
-
-$loop->setInterval(
-  function () use ($write) {
-    fwrite($write, microtime(TRUE)."\n");
-  },
-  1000
-);
-
-$stream->open();
-$loop->run();

example/timetalk.php

-<?php
-include(__DIR__.'/../vendor/autoload.php');
-
-use Carica\Io;
-
-$loop = Io\Event\Loop\Factory::get();
-
-$clients = array();
-
-$server = new Io\Network\Server();
-$server->events()->on(
-  'connection',
-  function ($stream) use (&$clients) {
-    echo "Client connected: $stream\n";
-    $clients[] = new Io\Network\Connection($stream);
-  }
-);
-
-$loop->setInterval(
-  function () use (&$clients) {
-    echo "Send time to ".count($clients)." clients\n";
-    foreach ($clients as $index => $client) {
-      /**
-       * @var Io\Network\Connection $client
-       */
-      if ($client->isActive()) {
-        $client->write(date(DATE_ATOM)."\n");
-      } else {
-        echo "Removing inactive client\n";
-        unset($clients[$index]);
-      }
-    }
-  },
-  1000
-);
-
-$server->listen(8080);
-
-$loop->run();

phpunit.xml

-<phpunit
-  backupGlobals="false"
-  backupStaticAttributes="false"
-  syntaxCheck="false">
-  <testsuites>
-    <testsuite name="Carica\Io">
-      <directory suffix="Test.php">tests</directory>
-    </testsuite>
-  </testsuites>
-  <filter>
-    <whitelist addUncoveredFilesFromWhitelist="true">
-      <directory>src</directory>
-    </whitelist>
-  </filter>
-  <logging>
-    <log type="coverage-html" target="./build/coverage" title="Carica Io" 
-      charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
-  </logging>
-</phpunit>

src/ByteArray.php

-<?php
-
-namespace Carica\Io {
-
-  /**
-   * Flexible access to an array of bytes, allow bit handling
-   */
-  class ByteArray implements \ArrayAccess, \IteratorAggregate, \Countable {
-
-    const BIT_ONE = 1;
-    const BIT_TWO = 2;
-    const BIT_THREE = 4;
-    const BIT_FOUR = 8;
-    const BIT_FIVE = 16;
-    const BIT_SIX = 32;
-    const BIT_SEVEN = 64;
-    const BIT_EIGHT = 128;
-
-    private $_bytes = array();
-    private $_length = 0;
-
-    /**
-     * Create array of bytes and set length.
-     *
-     * @param integer $length
-     * @throws \OutOfRangeException
-     */
-    public function __construct($length = 1) {
-      $this->setLength($length);
-    }
-
-    /**
-     * Resize the byte array, additional bytes will be filled with zero.
-     *
-     * @param integer $length
-     * @throws \OutOfRangeException
-     */
-    public function setLength($length) {
-      if ((int)$length < 1) {
-        throw new \OutOfRangeException('Zero or negative length is not possible');
-      }
-      $difference = $length - $this->_length;
-      if ($difference > 0) {
-        $this->_bytes = array_merge($this->_bytes, array_fill($this->_length, $difference, 0));
-      } elseif ($difference < 0) {
-        $this->_bytes = array_slice($this->_bytes, 0, $difference);
-      }
-      $this->_length = (int)$length;
-    }
-
-    /**
-     * Return teh current byte length
-     *
-     * @return integer
-     */
-    public function getLength() {
-      return $this->_length;
-    }
-
-    /**
-     * Get the byte array as an binary string.
-     *
-     * @return string
-     */
-    public function __toString() {
-      return call_user_func_array('pack', array_merge(array("C*"), $this->_bytes));
-    }
-
-    /**
-     * read the bytes from an binary string
-     *
-     * @param string $string
-     * @param boolean $resize to binary string length
-     * @throws \OutOfBoundsException
-     */
-    public function fromString($string, $resize = FALSE) {
-      if ($resize && strlen($string) != $this->getLength()) {
-        $this->setLength(strlen($string));
-      }
-      $bytes = array_slice(unpack("C*", "\0".$string), 1);
-      if (count($bytes) >= $this->_length) {
-        for ($i = 0; $i < $this->_length; ++$i) {
-          $this->_bytes[$i] = $bytes[$i];
-        }
-      } else {
-        throw new \OutOfBoundsException(
-          sprintf(
-            'Maximum length is "%d". Got "%d".', $this->_length, count($bytes)
-          )
-        );
-      }
-    }
-
-    /**
-     * Read an hexadecimal encoded binary string
-     *
-     * @param string $string
-     * @param boolean $resize
-     * @throws \OutOfBoundsException
-     */
-    public function fromHexString($string, $resize = FALSE) {
-      $string = str_replace(' ', '', $string);
-      $length = floor(strlen($string) / 2);
-      if ($resize && $length != $this->getLength()) {
-        $this->setLength($length);
-      }
-      if ($length >= $this->_length) {
-        for ($i = 0; $i < $this->_length; ++$i) {
-          $this->_bytes[$i] = hexdec(substr($string, $i * 2, 2));
-        }
-      } else {
-        throw new \OutOfBoundsException(
-          sprintf(
-            'Maximum length is "%d". Got "%d".', $this->_length, $length
-          )
-        );
-      }
-    }
-
-    /**
-     * Read an hexadecimal encoded binary string
-     *
-     * @param array $bytes
-     * @param boolean $resize
-     * @throws \OutOfBoundsException
-     */
-    public function fromArray(array $bytes, $resize = FALSE) {
-      $length = count($bytes);
-      if ($resize && $length != $this->getLength()) {
-        $this->setLength($length);
-      }
-      if ($length >= $this->_length) {
-        foreach (array_values($bytes) as $index => $byte) {
-          $this->_bytes[$index] = $byte;
-        }
-      } else {
-        throw new \OutOfBoundsException(
-          sprintf(
-            'Maximum length is "%d". Got "%d".', $this->_length, $length
-          )
-        );
-      }
-    }
-
-    /**
-     * Get the byte array as an hexdec string.
-     *
-     * @param string $separator
-     *
-     * @return string
-     */
-    public function asHex($separator = '') {
-      $result = '';
-      foreach ($this->_bytes as $byte) {
-        $result .= str_pad(dechex($byte), 2, '0', STR_PAD_LEFT).$separator;
-      }
-      return empty($separator)
-        ? $result
-        : substr($result, 0, -strlen($separator));
-    }
-
-    /**
-     * Get the bytes as bit string seperated by spaces.
-     *
-     * @return string
-     */
-    public function asBitString() {
-      $result = '';
-      foreach ($this->_bytes as $byte) {
-        $result .= ' '.str_pad(decbin($byte), 8, '0', STR_PAD_LEFT);
-      }
-      return substr($result, 1);
-    }
-
-    /**
-     * Get the bytes as array of bytes, only needed for array functions.
-     *
-     * @return array
-     */
-    public function asArray() {
-      return $this->_bytes;
-    }
-
-    /**
-     * Check if the specified byte or bit offset exists.
-     *
-     * If the $offset is an array the first element is the byte index and the second the bin index.
-     *
-     * If the $offset is an integer it is the byte offset.
-     *
-     * @see ArrayAccess::offsetExists()
-     * @param integer|array(integer,integer) $offset
-     * @return integer|boolean
-     */
-    public function offsetExists($offset) {
-      try {
-        $this->validateOffset($offset);
-      } catch (\OutOfBoundsException $e) {
-        return FALSE;
-      }
-      return TRUE;
-    }
-
-    /**
-     * Read if the specified byte or bit offset exists.
-     *
-     * If the $offset is an array the first element is the byte index and the second the bin index.
-     * The result in this case is boolean.
-     *
-     * If the $offset is an integer it is the byte offset and the result is the byte values as
-     * integer.
-     *
-     * Examples:
-     *   $byte = $bytes[0]; // read the first byte
-     *   $bit = $bytes[[0, 7]]; // read the highest bit of the first byte
-     *
-     * @see ArrayAccess::offsetGet()
-     * @param integer|array(integer,integer) $offset
-     * @return integer|boolean
-     */
-    public function offsetGet($offset) {
-      $this->validateOffset($offset);
-      if (is_array($offset)) {
-        $bit = ($offset[1] > 0) ? 1 << $offset[1] : 1;
-        return ($this->_bytes[$offset[0]] & $bit) == $bit;
-      } else {
-        return $this->_bytes[$offset];
-      }
-    }
-
-    /**
-     * Write if the specified byte or bit offset exists.
-     *
-     * If the $offset is an array the first element is the byte index and the second the bin index.
-     * The value has to be boolean in this case.
-     *
-     * If the $offset is an integer it is the byte offset and the value is the byte value as
-     * integer.
-     *
-     * Examples:
-     *   $bytes[0] = 42; // write the first byte
-     *   $bytes[[0, 7]] = TRUE; // set the highest bit of the first byte
-     *
-     * @see ArrayAccess::offsetSet()
-     * @param integer|array(integer,integer) $offset
-     * @param integer|boolean $value
-     */
-    public function offsetSet($offset, $value) {
-      $this->validateOffset($offset);
-      if (is_array($offset)) {
-        $bit = ($offset[1] > 0) ? 1 << $offset[1] : 1;
-        if ($value) {
-          $this->_bytes[$offset[0]] = $this->_bytes[$offset[0]] | $bit;
-        } else {
-          $this->_bytes[$offset[0]] = $this->_bytes[$offset[0]] & ~$bit;
-        }
-      } else {
-        $this->validateValue($value);
-        $this->_bytes[$offset] = $value;
-      }
-    }
-
-    /**
-     * Reset an byte or bit
-     *
-     * If the index spezifies a byte it is set to zero. If it spdifies and bit it is disabled.
-     *
-     * @see ArrayAccess::offsetUnset()
-     */
-    public function offsetUnset($offset) {
-      $this->offsetSet($offset, is_array($offset) ? FALSE : 0);
-    }
-
-    /**
-     * Validate the given offset is usable as byte or bit offset
-     *
-     * @param integer|array(integer,integer) $offset
-     * @throws \OutOfBoundsException
-     */
-    private function validateOffset($offset) {
-      if (is_array($offset)) {
-        $this->validateBitOffset($offset);
-      } else {
-        if ($offset < 0 || $offset >= $this->_length) {
-          throw new \OutOfBoundsException(
-            sprintf(
-              'Maximum byte index is "%d". Got "%d".', $this->_length - 1, $offset
-            )
-          );
-        }
-      }
-    }
-
-    /**
-     * Validate the given offset is usable as bit offset
-     *
-     * @param array(integer,integer) $offset
-     * @throws \OutOfBoundsException
-     */
-    private function validateBitOffset(array $offset) {
-      if (count($offset) != 2) {
-        throw new \OutOfBoundsException(
-          sprintf(
-            'Bit index needs two elements (byte and bit index). Got "%d".', count($offset)
-          )
-        );
-      }
-      $this->validateOffset($offset[0]);
-      if ($offset[1] < 0 || $offset[1] >= 8) {
-        throw new \OutOfBoundsException(
-          sprintf(
-            'Maximum bit index is "7". Got "%d".', $offset[1]
-          )
-        );
-      }
-    }
-
-    /**
-     * Validate the given value is a storeable in a single byte
-     *
-     * @param integer $value
-     * @throws \OutOfRangeException
-     */
-    private function validateValue($value) {
-      if (($value < 0 || $value > 255)) {
-        throw new \OutOfRangeException(
-          sprintf('Byte value expected (0-255). Got "%d"', $value)
-        );
-      }
-    }
-
-    /**
-     * Allow to iterate the bytes
-     * @return \Iterator
-     */
-    public function getIterator() {
-      return new \ArrayIterator($this->_bytes);
-    }
-
-    /**
-     * Return byte count
-     *
-     * @return Integer
-     */
-    public function count() {
-      return count($this->_bytes);
-    }
-
-    /**
-     * Create an ByteArray from an hexadecimal byte string
-     * @param string $hexString
-     * @return \Carica\Io\ByteArray
-     */
-    public static function createFromHex($hexString) {
-      $bytes = new ByteArray();
-      $bytes->fromHexString($hexString, TRUE);
-      return $bytes;
-    }
-
-    /**
-     * Create a new ByteArray from an array of bytes
-     *
-     * @param array $array
-     * @return \Carica\Io\ByteArray
-     */
-    public static function createFromArray(array $array) {
-      $bytes = new ByteArray();
-      $bytes->fromArray($array, TRUE);
-      return $bytes;
-    }
-  }
-}

src/Callbacks.php

-<?php
-
-namespace Carica\Io {
-
-  /**
-   * Manage a list Callable elements, the list can be uses as one callable, too.
-   *
-   * @property Callable add
-   * @property Callable remove
-   * @property Callable fire
-   * @property Callable lock
-   * @property Callable disable
-   */
-  class Callbacks implements \IteratorAggregate, \Countable {
-
-    private $_callbacks = array();
-    private $_disabled = FALSE;
-    private $_locked = FALSE;
-    private $_fired = FALSE;
-
-    /**
-     * Add a new callable, and return itself for chaining
-     *
-     * @param callable $callback
-     * @return Callbacks
-     */
-    public function add(Callable $callback) {
-      $hash = $this->getCallableHash($callback);
-      if (!($this->_locked || isset($this->_callbacks[$hash]))) {
-        $this->_callbacks[$hash] = $callback;
-      }
-      return $this;
-    }
-
-    /**
-     * Remove an callable, and return itself for chaining
-     *
-     * @param callable $callback
-     * @return Callbacks
-     */
-    public function remove(Callable $callback) {
-      $hash = $this->getCallableHash($callback);
-      if (!$this->_locked && isset($this->_callbacks[$hash])) {
-        unset($this->_callbacks[$hash]);
-      }
-      return $this;
-    }
-
-    /**
-     * Remove all callables
-     *
-     * @return Callbacks
-     */
-    public function clear() {
-      if (!$this->_locked) {
-        $this->_callbacks = array();
-      }
-      return $this;
-    }
-
-    /**
-     * Validate if the given callable is ion the list.
-     *
-     * @param callable $callback
-     * @return boolean
-     */
-    public function has(Callable $callback) {
-      $hash = $this->getCallableHash($callback);
-      return isset($this->_callbacks[$hash]);
-    }
-
-    /**
-     * Lock the list, do now allow chanes any more.
-     *
-     * @return Callbacks
-     */
-    public function lock() {
-      $this->_locked = TRUE;
-      return $this;
-    }
-
-    /**
-     * Validate if the list is locked
-     *
-     * @return boolean
-     */
-    public function locked() {
-      return $this->_locked;
-    }
-
-    /**
-     * Disable the execution of the callbacks in the list
-     *
-     * @return Callbacks
-     */
-    public function disable() {
-      $this->_disabled = TRUE;
-      return $this;
-    }
-
-    /**
-     * Validate if the callbacks are disabled
-     *
-     * @return boolean
-     */
-    public function disabled() {
-      return $this->_disabled;
-    }
-
-    /**
-     * Execute the callbacks
-     *
-     * @param mixed [$argument,...]
-     */
-    public function fire() {
-      if (!$this->_disabled) {
-        $this->_fired = TRUE;
-        $arguments = func_get_args();
-        foreach ($this->_callbacks as $callback) {
-          call_user_func_array($callback, $arguments);
-        }
-      }
-    }
-
-    /**
-     * Validate if the callbacks were executed at least once
-     *
-     * @return boolean
-     */
-    public function fired() {
-      return $this->_fired;
-    }
-
-    /**
-     * If the object is used as an functor, call fire()
-     *
-     * @param mixed [$argument,...]
-     * @return mixed
-     */
-    public function __invoke() {
-      return call_user_func_array(array($this, 'fire'), func_get_args());
-    }
-
-    /**
-     * Allow to fetch the methods of this object as anonymus functions
-     *
-     * @throws \LogicException
-     * @param string $name
-     * @return \Callable
-     */
-    public function __get($name) {
-      if (method_exists($this, $name)) {
-        $callback = array($this, $name);
-        return function() use ($callback) {
-          call_user_func_array($callback, func_get_args());
-        };
-      }
-      throw new \LogicException('Unknown property: '.$name);
-    }
-
-    /**
-     * Block changes to the object properties
-     *
-     * @param string $name
-     * @param mixed $value
-     *
-     * @throws \LogicException
-     */
-    public function __set($name, $value) {
-      throw new \LogicException('Unknown/Readonly property: '.$name);
-    }
-
-    /**
-     * IteratorAggregate interface for the stored callables
-     *
-     * @see IteratorAggregate::getIterator()
-     * @return \Iterator
-     */
-    public function getIterator() {
-      return new \ArrayIterator(array_values($this->_callbacks));
-    }
-
-    /**
-     * Countable interface, return the number of stored callables
-     *
-     * @see Countable::count()
-     * @return integer
-     */
-    public function count() {
-      return count($this->_callbacks);
-    }
-
-    /**
-     * Get an hash for the provided callable/object
-     *
-     * @param Callable|object $callable
-     * @return string
-     */
-    private function getCallableHash($callable) {
-      if (is_object($callable)) {
-        return spl_object_hash($callable);
-      } elseif (is_array($callable)) {
-        return md5($this->getCallableHash($callable[0]), $callable[1]);
-      } else {
-        return md5((string)$callable);
-      }
-    }
-  }
-}

src/Deferred.php

-<?php
-
-namespace Carica\Io {
-
-  /**
-  * A deferred object implementation, allows to schedule callbacks for
-  * execution after a condition is meet or not.
-  *
-  */
-  class Deferred {
-
-    /**
-     * Default state - not yet finalized
-     * @var string
-     */
-    const STATE_PENDING = 'pending';
-    /**
-     * Final state, object was resolved, the action was successful
-     * @var string
-     */
-    const STATE_RESOLVED = 'resolved';
-
-    /**
-     * Final state, object was rejected, the action failed
-     *
-     * @var string
-     */
-    const STATE_REJECTED = 'rejected';
-
-    /**
-     * current state
-     * .
-     * @var string
-     */
-    private $_state = self::STATE_PENDING;
-    /**
-     * An promise for this object
-     * .
-     * @var Deferred\Promise
-     */
-    private $_promise = NULL;
-
-    /**
-     * Callbacks if the object is resolved
-     * .
-     * @var Callable|Callbacks
-     */
-    private $_done = NULL;
-    /**
-     * Callbacks if the object is rejected
-     * .
-     * @var Callable|Callbacks
-     */
-    private $_failed = NULL;
-    /**
-     * Callbacks if the object is notified about a progress
-     * .
-     * @var Callable|Callbacks
-     */
-    private $_progress = NULL;
-
-    /**
-     * buffer for the arguments of the resolve/reject function,
-     * used to execute functions, that are added after the object was finalized
-     * .
-     * @var array
-     */
-    private $_finishArguments = array();
-    /**
-     * Buffer for the last progress notification arguments, used
-     * to bring new callback up to date.
-     * .
-     * @var NULL|array
-     */
-    private $_progressArguments = NULL;
-
-    /**
-     * Create object and intialize callback lists
-     */
-    public function __construct() {
-      $this->_done = new Callbacks();
-      $this->_failed = new Callbacks();
-      $this->_progress = new Callbacks();
-    }
-
-    /**
-     * Add a callback that will be execute if the object is finalized with
-     * resolved or reject
-     *
-     * @param Callable $callback
-     * @return Deferred
-     */
-    public function always(Callable $callback) {
-      $this->_done->add($callback);
-      $this->_failed->add($callback);
-      if ($this->_state != self::STATE_PENDING) {
-        call_user_func_array($callback, $this->_finishArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Add a callback that will be executed if the object is resolved
-     *
-     * @param Callable $callback
-     * @return Deferred
-     */
-    public function done(Callable $callback) {
-      $this->_done->add($callback);
-      if ($this->_state == self::STATE_RESOLVED) {
-        call_user_func_array($callback, $this->_finishArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Add a callback that will be eecuted if the object was rejected
-     *
-     * @param Callable $callback
-     * @return Deferred
-     */
-    public function fail(Callable $callback) {
-      $this->_failed->add($callback);
-      if ($this->_state == self::STATE_REJECTED) {
-        call_user_func_array($callback, $this->_finishArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Validate if the object was finilized using reject.
-     *
-     * @return string
-     */
-    public function isRejected() {
-      return $this->_state == self::STATE_REJECTED;
-    }
-
-    /**
-     * Validate if the object was finilized using resolve.
-     *
-     * @return string
-     */
-    public function isResolved() {
-      return $this->_state == self::STATE_RESOLVED;
-    }
-
-    /**
-     * Notify the object about the progress
-     */
-    public function notify() {
-      if ($this->_state == self::STATE_PENDING) {
-        $this->_progressArguments = func_get_args();
-        call_user_func_array($this->_progress, $this->_progressArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Utility method to filter and/or chain Deferreds.
-     *
-     * @param Callable $doneFilter
-     * @param Callable $failFilter
-     * @param Callable $progressFilter
-     * @return Deferred\Promise
-     */
-    public function pipe(
-      Callable $doneFilter = NULL,
-      Callable $failFilter = NULL,
-      Callable $progressFilter = NULL
-    ) {
-      $defer = new Deferred();
-      $this->done(
-        function () use ($defer, $doneFilter){
-          if ($doneFilter) {
-            $defer->resolve(call_user_func_array($doneFilter, func_get_args()));
-          } else {
-            call_user_func_array(array($defer, 'resolve'), func_get_args());
-          }
-        }
-      );
-      $this->fail(
-        function () use ($defer, $failFilter){
-          if ($failFilter) {
-            $defer->reject(call_user_func_array($failFilter, func_get_args()));
-          } else {
-            call_user_func_array(array($defer, 'reject'), func_get_args());
-          }
-        }
-      );
-      $this->progress(
-        function () use ($defer, $progressFilter){
-          if ($progressFilter) {
-            $defer->notify(call_user_func_array($progressFilter, func_get_args()));
-          } else {
-            call_user_func_array(array($defer, 'notify'), func_get_args());
-          }
-        }
-      );
-      return $defer->promise();
-    }
-
-    /**
-     * Add a callback that will be executed if the object is notified about progress
-     *
-     * @param Callable $callback
-     * @return Deferred
-     */
-    public function progress(Callable $callback) {
-      $this->_progress->add($callback);
-      if (NULL !== $this->_progressArguments) {
-        call_user_func_array($callback, $this->_progressArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Creates and returns a promise attached to this object, a promise is used to
-     * attach callbacks and validate the status. But has no methods to change the status.
-     *
-     * @return Deferred\Promise
-     */
-    public function promise() {
-      if (NULL === $this->_promise) {
-        $this->_promise = new Deferred\Promise($this);
-      }
-      return $this->_promise;
-    }
-
-    /**
-     * Finalize the object and set the status to rejected - the action has failed.
-     * This will execute all callbacks attached with fail() or always()
-     *
-     * @return Deferred
-     */
-    public function reject() {
-      if ($this->_state == self::STATE_PENDING) {
-        $this->_finishArguments = func_get_args();
-        $this->_state = self::STATE_REJECTED;
-        call_user_func_array($this->_failed, $this->_finishArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Finalize the object and set the status to rejected - the action was successful.
-     * This will execute all callbacks attached with done() or always()
-     *
-     * @return Deferred
-     */
-    public function resolve() {
-      if ($this->_state == self::STATE_PENDING) {
-        $this->_finishArguments = func_get_args();
-        $this->_state = self::STATE_RESOLVED;
-        call_user_func_array($this->_done, $this->_finishArguments);
-      }
-      return $this;
-    }
-
-    /**
-     * Return the state string. Here are constants for each state, too.
-     *
-     * @return string
-     */
-    public function state() {
-      return $this->_state;
-    }
-
-    /**
-     * Add handlers to be called when the Deferred object is resolved
-     * or rejected or notified about progress. Basically a shortcut for
-     * done(), fail() and progress().
-     *
-     * @param Callable|array(Callable) $done
-     * @param Callable|array(Callable) $fail
-     * @param Callable|array(Callable) $progress
-     * @return Deferred
-     */
-    public function then($done = NULL, $fail = NULL, $progress = NULL) {
-      $this->addCallbacksIfProvided(array($this, 'done'), $done);
-      $this->addCallbacksIfProvided(array($this, 'fail'), $fail);
-      $this->addCallbacksIfProvided(array($this, 'progress'), $progress);
-      return $this;
-    }
-
-    /**
-     * Check if $callbacks is a single callback or an array of callbacks.
-     * The $add parameter is the method used to add the actual callbacks to the
-     * deferred object.
-     *
-     * @param Callable $add
-     * @param Callable|array(Callable) $callbacks
-     */
-    private function addCallbacksIfProvided($add, $callbacks) {
-      if (is_callable($callbacks)) {
-        $add($callbacks);
-      } elseif (is_array($callbacks)) {
-        foreach ($callbacks as $callback) {
-          $add($callback);
-        }
-      }
-    }
-
-    /**
-     * Static method to the create a new Deferred object.
-     *
-     * @return Deferred
-     */
-    public static function create() {
-      return new Deferred();
-    }
-
-    /**
-     * Provides a way to execute callback functions based on one or more
-     * objects, usually Deferred objects that represent asynchronous events.
-     *
-     * @return Deferred\Promise
-     */
-    public static function when() {
-      $arguments = func_get_args();
-      $counter = count($arguments);
-      if ($counter == 1) {
-        $argument = $arguments[0];
-        if ($argument instanceOf Deferred) {
-          return $argument->promise();
-        } elseif ($argument instanceOf Deferred\Promise) {
-          return $argument;
-        } else {
-          $defer = new Deferred();
-          $defer->resolve($argument);
-          return $defer->promise();
-        }
-      } elseif ($counter > 0) {
-        $master = new Deferred();
-        $resolveArguments = array();
-        foreach ($arguments as $index => $argument) {
-          /**
-           * @var Deferred\Promise $argument
-           */
-          if ($argument instanceOf Deferred || $argument instanceOf Deferred\Promise) {
-            $argument
-              ->done(
-                function() use ($master, $index, &$counter, &$resolveArguments) {
-                  $resolveArguments[$index] = func_get_args();
-                  if (--$counter == 0) {
-                    ksort($resolveArguments);
-                    call_user_func_array(array($master, 'resolve'), $resolveArguments);
-                  }
-                }
-              )
-              ->fail(
-                function() use ($master) {
-                  call_user_func_array(array($master, 'reject'), func_get_args());
-                }
-              );
-          } else {
-            $resolveArguments[$index] = array($argument);
-            if (--$counter == 0) {
-              ksort($resolveArguments);
-              call_user_func_array(array($master, 'resolve'), $resolveArguments);
-            }
-          }
-        }
-        return $master->promise();
-      } else {
-        $defer = new Deferred();
-        $defer->resolve();
-        return $defer->promise();
-      }
-    }
-  }
-}

src/Deferred/MySQL.php

-<?php
-
-namespace Carica\Io\Deferred {
-
-  use Carica\Io;
-  use Carica\Io\Event;
-
-  class MySQL {
-
-    use Event\Loop\Aggregation;
-
-    /**
-     * @var \mysqli
-     */
-    private $_mysqli = NULL;
-
-    public function __construct($mysqli) {
-      $this->_mysqli = $mysqli;
-    }
-
-    public function __invoke() {
-      return call_user_func_array(array($this, 'query'), func_get_args());
-    }
-
-    public function query($sql) {
-      $defer = new Io\Deferred();
-      $mysqli = $this->_mysqli;
-      $mysqli->query($sql, MYSQLI_ASYNC);
-      $this->loop()->setInterval(
-        function() use ($defer, $mysqli) {
-          $links = $errors = $reject = array($mysqli);
-          if ($mysqli->poll($links, $errors, $reject, 0, 0)) {
-            if ($result = $mysqli->reap_async_query()) {
-              $defer->resolve($result);
-            } else {
-              $defer->reject();
-            }
-          }
-        },
-        50
-      );
-      return $defer->promise();
-    }
-  }
-}

src/Deferred/Promise.php

-<?php
-
-namespace Carica\Io\Deferred {
-
-  use Carica\Io;
-
-  class Promise {
-
-    protected $_defer = NULL;
-
-    /**
-     * Create the promise for a Deferred object.
-     *
-     * @param Io\Deferred $defer
-     */
-    public function __construct(Io\Deferred $defer) {
-      $this->_defer = $defer;
-    }
-
-    /**
-     * Add a callback that will be execute if the object is finalized with
-     * resolved or reject
-     *
-     * @param Callable $callback
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function always(Callable $callback) {
-      $this->_defer->always($callback);
-      return $this;
-    }
-
-    /**
-     * Add a callback that will be executed if the object is resolved
-     *
-     * @param Callable $callback
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function done(Callable $callback) {
-      $this->_defer->done($callback);
-      return $this;
-    }
-
-    /**
-     * Add a callback that will be eecuted if the object was rejected
-     *
-     * @param Callable $callback
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function fail(Callable $callback) {
-      $this->_defer->fail($callback);
-      return $this;
-    }
-
-    /**
-     * Utility method to filter and/or chain Deferreds.
-     *
-     * @param Callable $doneFilter
-     * @param Callable $failFilter
-     * @param Callable $progressFilter
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function pipe(
-      Callable $doneFilter = NULL,
-      Callable $failFilter = NULL,
-      Callable $progressFilter = NULL
-    ) {
-      return $this->_defer->pipe($doneFilter, $failFilter, $progressFilter);
-    }
-
-    /**
-     * Add a callback that will be executed if the object is notified about progress
-     *
-     * @param Callable $callback
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function progress(Callable $callback) {
-      $this->_defer->progress($callback);
-      return $this;
-    }
-
-    /**
-     * Return the state string. Here are constants for each state, too.
-     *
-     * @return string
-     */
-    public function state() {
-      return $this->_defer->state();
-    }
-
-    /**
-     * Add handlers to be called when the Deferred object is resolved
-     * or rejected or notified about progress. Basically a shortcut for
-     * done(), fail() and progress().
-     *
-     * @param Callable|array(Callable) $done
-     * @param Callable|array(Callable) $fail
-     * @param Callable|array(Callable) $progress
-     * @return \Carica\Io\Deferred\Promise
-     */
-    public function then($done = NULL, $fail = NULL, $progress = NULL) {
-      $this->_defer->then($done, $fail, $progress);
-      return $this;
-    }
-  }
-}

src/Event/Emitter.php

-<?php
-
-namespace Carica\Io\Event {
-
-  class Emitter {
-
-    private $_events = array();
-
-    /**
-     * Add a listener object. If a callable is added, it is wrapped into a listener
-     *
-     * @param string $event
-     * @param \Callable|Emitter\Listener $listener
-     */
-    public function on($event, $listener) {
-      $listener = $listener instanceOf Emitter\Listener
-        ? $listener : new Emitter\Listener\On($this, $event, $listener);
-      $this->_events[$event][] = $listener;
-      $this->emit('newListener', $listener);
-    }
-
-    /**
-     * Add a listener that is removed after it's first call. If a callable is added, it is wrapped
-     * into a listener
-     *
-     * @param string $event
-     * @param \Callable|Emitter\Listener $listener
-     */
-    public function once($event, $listener) {
-      $listener = $listener instanceOf Emitter\Listener\Once
-        ? $listener : new Emitter\Listener\Once($this, $event, $listener);
-      $this->on($event, $listener);
-    }
-
-    /**
-     * Remode the specified listenr from the event
-     *
-     * @param string $event
-     * @param \Callable|Emitter\Listener $listener
-     */
-    public function removeListener($event, $listener) {
-      if (isset($this->_events[$event])) {
-        foreach ($this->_events[$event] as $key => $eventListener) {
-          /**
-           * @var Emitter\Listener $eventListener
-           */
-          if ($eventListener === $listener || $eventListener->getCallback() == $listener) {
-            unset($this->_events[$event][$key]);
-          }
-        }
-      }
-    }
-
-    /**
-     * Remove all listener of an event
-     *
-     * @param string $event
-     */
-    public function removeAllListeners($event) {
-      $this->_events[$event] = array();
-    }
-
-    /**
-     * Return an list of a listeners attached to the event
-     *
-     * @param string $event
-     * @return array(\Callable|Emitter\Listener)
-     */
-    public function listeners($event) {
-      return isset($this->_events[$event]) ? $this->_events[$event] : array();
-    }
-
-    /**
-     * Emit an event to all attached listeners
-     *
-     * @param string $event
-     * @param mixed [$argument,...]
-     */
-    public function emit($event) {
-      $arguments = func_get_args();
-      array_shift($arguments);
-      if (isset($this->_events[$event])) {
-        foreach ($this->_events[$event] as $listener) {
-          call_user_func_array($listener, $arguments);
-        }
-      }
-    }
-  }
-}

src/Event/Emitter/Aggregation.php

-<?php
-
-namespace Carica\Io\Event\Emitter {
-
-  use Carica\Io\Event;
-
-  trait Aggregation {
-
-    /**
-     * @var Event\Emitter
-     */
-    private $_eventEmitter = NULL;
-
-    /**
-     * Getter/Setter for the event emitter including implicit create.
-     *
-     * @param Event\Emitter $emitter
-     * @return Event\Emitter
-     */
-    public function events(Event\Emitter $emitter = NULL) {
-      if (NULL !== $emitter) {
-        $this->_eventEmitter = $emitter;
-      } elseif (NULL === $this->_eventEmitter) {
-        $this->_eventEmitter = new Event\Emitter();
-      }
-      return $this->_eventEmitter;
-    }
-
-    /**
-     * Avoid to create the emitter object just for emitting, without any callbacks attached
-     *
-     * @param $event
-     */
-    public function emitEvent($event) {
-      if (isset($this->_eventEmitter) && !empty($event)) {
-        call_user_func_array(array($this->_eventEmitter, 'emit'), func_get_args());
-      }
-    }
-  }
-}

src/Event/Emitter/Listener.php

-<?php
-
-namespace Carica\Io\Event\Emitter {
-
-  interface Listener {
-
-    function __invoke();
-
-    function getCallback();
-  }
-}

src/Event/Emitter/Listener/On.php

-<?php
-
-namespace Carica\Io\Event\Emitter\Listener  {
-
-  use Carica\Io\Event;
-
-  /**
-   * @property Event\Emitter $emitter
-   * @property string $event
-   * qproperty Callable $callback
-   */
-  class On implements Event\Emitter\Listener {
-
-    private $_emitter = NULL;
-    private $_event = NULL;
-    private $_callback = NULL;
-
-    public function __construct(Event\Emitter $emitter, $event, $callback) {
-      $this->_emitter = $emitter;
-      $this->_event = $event;
-      $this->_callback = $callback;
-    }
-
-    public function __isset($name) {
-      switch ($name) {
-      case 'emitter' :
-      case 'event' :
-      case 'callback' :
-        return isset($this->{'_'.$name});
-      }
-      return FALSE;
-    }
-
-    public function __get($name) {
-      switch ($name) {
-      case 'emitter' :
-      case 'event' :
-      case 'callback' :
-        return $this->{'_'.$name};
-      }
-      throw new \LogicException(sprintf('Property %s::$%s does not exists.', get_class($this), $name));
-    }
-
-    public function __set($name, $value) {
-      throw new \LogicException(sprintf('%s is immutable.', get_class($this)));
-    }
-
-    public function __unset($name) {
-      throw new \LogicException(sprintf('%s is immutable.', get_class($this)));
-    }
-
-    public function __invoke() {
-      call_user_func_array($this->_callback, func_get_args());
-    }
-
-    public function getCallback() {
-      return $this->_callback;
-    }
-  }
-}

src/Event/Emitter/Listener/Once.php

-<?php
-
-namespace Carica\Io\Event\Emitter\Listener {
-
-  use Carica\Io\Event;
-
-  /**
-   * @property Event\Emitter $emitter
-   * @property string $event
-   * qproperty Callable $callback
-   */
-  class Once extends On {
-
-    public function __invoke() {
-      $this->emitter->removeListener($this->event, $callback = $this->getCallback());
-      call_user_func_array($callback, func_get_args());
-    }
-  }
-}

src/Event/HasEmitter.php

-<?php
-
-namespace Carica\Io\Event {
-
-  use \Carica\Io\Event;
-
-  interface HasEmitter {
-
-    /**
-     * @param Event\Emitter $events
-     * @return Event\Emitter
-     */
-    function events(Event\Emitter $events = NULL);
-  }
-}

src/Event/HasLoop.php

-<?php
-
-namespace Carica\Io\Event {
-
-  use \Carica\Io\Event;
-
-  interface HasLoop {
-
-    /**
-     * @param Event\Loop $loop
-     * @return Event\Loop
-     */
-    function loop(Event\Loop $loop = NULL);
-  }
-}

src/Event/Loop.php

-<?php
-
-namespace Carica\Io\Event {
-
-  use Carica\Io;
-
-  interface Loop extends \Countable {
-
-    function setTimeout(Callable $callback, $milliseconds);
-
-    function setInterval(Callable $callback, $milliseconds);
-
-    function setStreamReader(Callable $callback, $stream);
-
-    function remove($listener);
-
-    function run(Io\Deferred\Promise $for = NULL);
-
-    function stop();
-
-  }
-
-}

src/Event/Loop/Aggregation.php

-<?php
-
-namespace Carica\Io\Event\Loop {
-
-  use Carica\Io\Event;
-
-  trait Aggregation {
-
-    /**
-     * @var Event\Loop
-     */
-    private $_eventLoop = NULL;
-
-    /**
-     * Getter/Setter for the event loop including implicit create. The create uses
-     * the factory fetching a global instance of the loop by default.
-     *
-     * @param Event\Loop $loop
-     * @return Event\Loop
-     */
-    public function loop(Event\Loop $loop = NULL) {
-      if (NULL !== $loop) {
-        $this->_eventLoop = $loop;
-      } elseif (NULL === $this->_eventLoop) {
-        $this->_eventLoop = Factory::get();
-      }
-      return $this->_eventLoop;
-    }
-  }
-}

src/Event/Loop/AlertReactor.php

-<?php
-
-namespace Carica\Io\Event\Loop {
-
-  use Carica\Io as Io;
-  use Alert as Alert;
-
-  class AlertReactor implements Io\Event\Loop {
-
-    /**
-     * @var Alert\Reactor
-     */
-    private $_reactor = NULL;
-
-    public function reactor(Alert\Reactor $loop = NULL) {
-      if (isset($reactor)) {
-        $this->_reactor = $reactor;
-      } elseif (NULL === $this->_reactor) {
-        $this->_reactor = (new Alert\ReactorFactory)->select();;
-      }
-      return $this->_reactor;
-    }
-
-    public function setTimeout(Callable $callback, $milliseconds) {
-      return $this->reactor()->once($callback, $milliseconds / 1000);
-    }
-
-    public function setInterval(Callable $callback, $milliseconds) {
-      return $this->reactor()->repeat($callback, $milliseconds / 1000);
-    }
-
-    public function setStreamReader(Callable $callback, $stream) {
-      return $this->reactor()->onREadable($stream, $callback, TRUE);
-    }
-
-    public function remove($watcherId) {
-      $this->reactor()->cancel($watcherId);
-    }
-
-    public function run(Io\Deferred\Promise $for = NULL) {
-      $reactor = $this->reactor();
-      if (isset($for) &&
-          $for->state() === Io\Deferred::STATE_PENDING) {
-        $for->always(
-          function () use ($reactor) {
-            $reactor->stop();
-          }
-        );
-      }
-      $reactor->run();
-    }
-
-    public function stop() {
-      $this->reactor()->stop();
-    }
-
-    public function count() {
-      return -1;
-    }
-  }
-}

src/Event/Loop/Factory.php

-<?php
-
-namespace Carica\Io\Event\Loop {
-
-  use Carica\Io;
-  use Carica\Io\Event;
-
-  class Factory {
-
-    const USE_STREAMSELECT = 'streamselect';
-    const USE_LIBEVENT = 'libevent';
-    const USE_REACT = 'react';
-    const USE_ALERT_REACTOR = 'alert-reactor';
-
-    /**
-     * @var Event\Loop
-     */
-    private static $_globalLoop = NULL;
-
-    /**
-     * @var null|int
-     */
-    private static $_useImplementation = NULL;
-
-    private static $_priority = array();
-
-    private static $_defaultPriority = array(
-      self::USE_REACT,
-      self::USE_LIBEVENT,
-      self::USE_STREAMSELECT
-    );
-
-    /**
-     * Create a event loop
-     *
-     * @param array $priority
-     * @return Event\Loop
-     */
-    public static function create(array $priority = NULL) {
-      switch (self::getImplementation($priority)) {
-      case self::USE_REACT :
-        return new React();
-      case self::USE_ALERT_REACTOR :
-        return new AlertReactor();
-      case self::USE_LIBEVENT :
-        return new Libevent(event_base_new());
-      default :
-        return new StreamSelect();
-      }
-    }
-
-    /**
-     * Determine the implementation that should be used
-     *
-     * @param array $priority
-     * @return string
-     */
-    public static function getImplementation(array $priority = NULL) {
-      $priority = self::getPriority($priority);
-      if (NULL === self::$_useImplementation ||
-          !in_array(self::$_useImplementation, $priority)) {
-        foreach ($priority as $implementation) {
-          switch ($implementation) {
-          case self::USE_ALERT_REACTOR :
-            if (interface_exists('\\Alert\\Reactor')) {
-              return self::$_useImplementation = self::USE_ALERT_REACTOR;
-            }
-            break;
-          case self::USE_REACT :
-            if (interface_exists('\\React\\EventLoop\\LoopInterface')) {
-              return self::$_useImplementation = self::USE_REACT;
-            }
-            break;
-          case self::USE_LIBEVENT :
-            if (extension_loaded('libeve