]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
[CORE][COMPOSER] Add hoa/consistency
authorDiogo Cordeiro <diogo@fc.up.pt>
Tue, 25 Jun 2019 09:35:31 +0000 (10:35 +0100)
committerDiogo Cordeiro <diogo@fc.up.pt>
Sat, 3 Aug 2019 16:47:27 +0000 (17:47 +0100)
Renamed curry to callable_left_curry

85 files changed:
composer.json
composer.lock
lib/callable_left_curry.php [new file with mode: 0644]
lib/curry.php [deleted file]
lib/util.php
tests/CurryTest.php
vendor/composer/autoload_classmap.php
vendor/composer/autoload_files.php
vendor/composer/autoload_psr4.php
vendor/composer/autoload_static.php
vendor/composer/installed.json
vendor/hoa/consistency/.State [new file with mode: 0644]
vendor/hoa/consistency/.gitignore [new file with mode: 0644]
vendor/hoa/consistency/.travis.yml [new file with mode: 0644]
vendor/hoa/consistency/Autoloader.php [new file with mode: 0644]
vendor/hoa/consistency/CHANGELOG.md [new file with mode: 0644]
vendor/hoa/consistency/Consistency.php [new file with mode: 0644]
vendor/hoa/consistency/Exception.php [new file with mode: 0644]
vendor/hoa/consistency/Prelude.php [new file with mode: 0644]
vendor/hoa/consistency/README.md [new file with mode: 0644]
vendor/hoa/consistency/Test/Unit/Autoloader.php [new file with mode: 0644]
vendor/hoa/consistency/Test/Unit/Consistency.php [new file with mode: 0644]
vendor/hoa/consistency/Test/Unit/Exception.php [new file with mode: 0644]
vendor/hoa/consistency/Test/Unit/Xcallable.php [new file with mode: 0644]
vendor/hoa/consistency/Xcallable.php [new file with mode: 0644]
vendor/hoa/consistency/composer.json [new file with mode: 0644]
vendor/hoa/event/.State [new file with mode: 0644]
vendor/hoa/event/.gitignore [new file with mode: 0644]
vendor/hoa/event/Bucket.php [new file with mode: 0644]
vendor/hoa/event/CHANGELOG.md [new file with mode: 0644]
vendor/hoa/event/Event.php [new file with mode: 0644]
vendor/hoa/event/Exception.php [new file with mode: 0644]
vendor/hoa/event/Listenable.php [new file with mode: 0644]
vendor/hoa/event/Listener.php [new file with mode: 0644]
vendor/hoa/event/Listens.php [new file with mode: 0644]
vendor/hoa/event/README.md [new file with mode: 0644]
vendor/hoa/event/Source.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Bucket.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Event.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Exception.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Listenable.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Listener.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Listens.php [new file with mode: 0644]
vendor/hoa/event/Test/Unit/Source.php [new file with mode: 0644]
vendor/hoa/event/composer.json [new file with mode: 0644]
vendor/hoa/exception/.State [new file with mode: 0644]
vendor/hoa/exception/.gitignore [new file with mode: 0644]
vendor/hoa/exception/CHANGELOG.md [new file with mode: 0644]
vendor/hoa/exception/Error.php [new file with mode: 0644]
vendor/hoa/exception/Exception.php [new file with mode: 0644]
vendor/hoa/exception/Group.php [new file with mode: 0644]
vendor/hoa/exception/Idle.php [new file with mode: 0644]
vendor/hoa/exception/README.md [new file with mode: 0644]
vendor/hoa/exception/Test/Unit/Error.php [new file with mode: 0644]
vendor/hoa/exception/Test/Unit/Exception.php [new file with mode: 0644]
vendor/hoa/exception/Test/Unit/Group.php [new file with mode: 0644]
vendor/hoa/exception/Test/Unit/Idle.php [new file with mode: 0644]
vendor/hoa/exception/composer.json [new file with mode: 0644]
vendor/paragonie/random_compat/LICENSE [new file with mode: 0644]
vendor/paragonie/random_compat/composer.json [new file with mode: 0644]
vendor/paragonie/random_compat/dist/random_compat.phar.pubkey [new file with mode: 0644]
vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc [new file with mode: 0644]
vendor/paragonie/random_compat/lib/byte_safe_strings.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/cast_to_int.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/error_polyfill.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_bytes_libsodium.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php [new file with mode: 0644]
vendor/paragonie/random_compat/lib/random_int.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/composer.lock [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/MSBLOB.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/OpenSSH.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS1.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS8.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PuTTY.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Raw.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/XML.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Exception/FileNotFoundException.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Exception/NoSupportedAlgorithmsException.php [new file with mode: 0644]
vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.php [new file with mode: 0644]

index 3c4eb61eb78a10a7e1626a31e2a5657386a2bd9f..11773a74ff46ad4513bdfe9311c93ac252140c8f 100644 (file)
@@ -19,6 +19,7 @@
         "apereo/phpcas": "^1.3",
         "diogocomposer/xmpphp": "^3.0",
         "ezyang/htmlpurifier": "^4.10",
+        "hoa/consistency": "^1.17.05.02",
         "masterminds/html5": "^2.6",
         "mf2/mf2": "^0.4.6",
         "michelf/php-markdown": "^1.8.0",
index 670b7973a962a91987f289e14884303c4ab999f7..5d4ab05e8f6778d8be89524dec737db2c214a57e 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "ac49a57ede587e949b9bad4b3c080a1d",
+    "content-hash": "1f145be7e041fab248e0ffa15684f12f",
     "packages": [
         {
             "name": "apereo/phpcas",
             ],
             "time": "2018-02-23T01:58:20+00:00"
         },
+        {
+            "name": "hoa/consistency",
+            "version": "1.17.05.02",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hoaproject/Consistency.git",
+                "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f",
+                "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f",
+                "shasum": ""
+            },
+            "require": {
+                "hoa/exception": "~1.0",
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "hoa/stream": "~1.0",
+                "hoa/test": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hoa\\Consistency\\": "."
+                },
+                "files": [
+                    "Prelude.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Ivan Enderlin",
+                    "email": "ivan.enderlin@hoa-project.net"
+                },
+                {
+                    "name": "Hoa community",
+                    "homepage": "https://hoa-project.net/"
+                }
+            ],
+            "description": "The Hoa\\Consistency library.",
+            "homepage": "https://hoa-project.net/",
+            "keywords": [
+                "autoloader",
+                "callable",
+                "consistency",
+                "entity",
+                "flex",
+                "keyword",
+                "library"
+            ],
+            "time": "2017-05-02T12:18:12+00:00"
+        },
+        {
+            "name": "hoa/event",
+            "version": "1.17.01.13",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hoaproject/Event.git",
+                "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54",
+                "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54",
+                "shasum": ""
+            },
+            "require": {
+                "hoa/consistency": "~1.0",
+                "hoa/exception": "~1.0"
+            },
+            "require-dev": {
+                "hoa/test": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hoa\\Event\\": "."
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Ivan Enderlin",
+                    "email": "ivan.enderlin@hoa-project.net"
+                },
+                {
+                    "name": "Hoa community",
+                    "homepage": "https://hoa-project.net/"
+                }
+            ],
+            "description": "The Hoa\\Event library.",
+            "homepage": "https://hoa-project.net/",
+            "keywords": [
+                "event",
+                "library",
+                "listener",
+                "observer"
+            ],
+            "time": "2017-01-13T15:30:50+00:00"
+        },
+        {
+            "name": "hoa/exception",
+            "version": "1.17.01.16",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/hoaproject/Exception.git",
+                "reference": "091727d46420a3d7468ef0595651488bfc3a458f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f",
+                "reference": "091727d46420a3d7468ef0595651488bfc3a458f",
+                "shasum": ""
+            },
+            "require": {
+                "hoa/consistency": "~1.0",
+                "hoa/event": "~1.0"
+            },
+            "require-dev": {
+                "hoa/test": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Hoa\\Exception\\": "."
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Ivan Enderlin",
+                    "email": "ivan.enderlin@hoa-project.net"
+                },
+                {
+                    "name": "Hoa community",
+                    "homepage": "https://hoa-project.net/"
+                }
+            ],
+            "description": "The Hoa\\Exception library.",
+            "homepage": "https://hoa-project.net/",
+            "keywords": [
+                "exception",
+                "library"
+            ],
+            "time": "2017-01-16T07:53:27+00:00"
+        },
         {
             "name": "masterminds/html5",
             "version": "2.6.0",
             ],
             "time": "2017-08-08T07:44:07+00:00"
         },
-        {
-            "name": "hoa/consistency",
-            "version": "1.17.05.02",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/hoaproject/Consistency.git",
-                "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f",
-                "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f",
-                "shasum": ""
-            },
-            "require": {
-                "hoa/exception": "~1.0",
-                "php": ">=5.5.0"
-            },
-            "require-dev": {
-                "hoa/stream": "~1.0",
-                "hoa/test": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Hoa\\Consistency\\": "."
-                },
-                "files": [
-                    "Prelude.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Ivan Enderlin",
-                    "email": "ivan.enderlin@hoa-project.net"
-                },
-                {
-                    "name": "Hoa community",
-                    "homepage": "https://hoa-project.net/"
-                }
-            ],
-            "description": "The Hoa\\Consistency library.",
-            "homepage": "https://hoa-project.net/",
-            "keywords": [
-                "autoloader",
-                "callable",
-                "consistency",
-                "entity",
-                "flex",
-                "keyword",
-                "library"
-            ],
-            "time": "2017-05-02T12:18:12+00:00"
-        },
-        {
-            "name": "hoa/event",
-            "version": "1.17.01.13",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/hoaproject/Event.git",
-                "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54",
-                "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54",
-                "shasum": ""
-            },
-            "require": {
-                "hoa/consistency": "~1.0",
-                "hoa/exception": "~1.0"
-            },
-            "require-dev": {
-                "hoa/test": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Hoa\\Event\\": "."
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Ivan Enderlin",
-                    "email": "ivan.enderlin@hoa-project.net"
-                },
-                {
-                    "name": "Hoa community",
-                    "homepage": "https://hoa-project.net/"
-                }
-            ],
-            "description": "The Hoa\\Event library.",
-            "homepage": "https://hoa-project.net/",
-            "keywords": [
-                "event",
-                "library",
-                "listener",
-                "observer"
-            ],
-            "time": "2017-01-13T15:30:50+00:00"
-        },
-        {
-            "name": "hoa/exception",
-            "version": "1.17.01.16",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/hoaproject/Exception.git",
-                "reference": "091727d46420a3d7468ef0595651488bfc3a458f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f",
-                "reference": "091727d46420a3d7468ef0595651488bfc3a458f",
-                "shasum": ""
-            },
-            "require": {
-                "hoa/consistency": "~1.0",
-                "hoa/event": "~1.0"
-            },
-            "require-dev": {
-                "hoa/test": "~2.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Hoa\\Exception\\": "."
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Ivan Enderlin",
-                    "email": "ivan.enderlin@hoa-project.net"
-                },
-                {
-                    "name": "Hoa community",
-                    "homepage": "https://hoa-project.net/"
-                }
-            ],
-            "description": "The Hoa\\Exception library.",
-            "homepage": "https://hoa-project.net/",
-            "keywords": [
-                "exception",
-                "library"
-            ],
-            "time": "2017-01-16T07:53:27+00:00"
-        },
         {
             "name": "hoa/file",
             "version": "1.17.07.11",
diff --git a/lib/callable_left_curry.php b/lib/callable_left_curry.php
new file mode 100644 (file)
index 0000000..37c9c1c
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * PHP 5.3 implementation of function currying, using native closures.
+ * On 5.2 and lower we use the fallback implementation in util.php
+ *
+ * @param callback $fn
+ * @param ... any remaining arguments will be appended to call-time params
+ * @return callback
+ */
+function callable_left_curry($fn) {
+    $extra_args = func_get_args();
+    array_shift($extra_args);
+    return function() use ($fn, $extra_args) {
+        $args = func_get_args();
+        return call_user_func_array($fn,
+            array_merge($args, $extra_args));
+    };
+}
diff --git a/lib/curry.php b/lib/curry.php
deleted file mode 100644 (file)
index 6136dcd..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * PHP 5.3 implementation of function currying, using native closures.
- * On 5.2 and lower we use the fallback implementation in util.php
- *
- * @param callback $fn
- * @param ... any remaining arguments will be appended to call-time params
- * @return callback
- */
-function curry($fn) {
-    $extra_args = func_get_args();
-    array_shift($extra_args);
-    return function() use ($fn, $extra_args) {
-        $args = func_get_args();
-        return call_user_func_array($fn,
-            array_merge($args, $extra_args));
-    };
-}
index 28d7bba3ed9e46eb10bd6315c4936c1cd86744c8..0866b32d55b10469d16eda102c44eefbd6c0cae2 100644 (file)
@@ -927,7 +927,7 @@ define('_URL_SCHEME_SINGLE_COLON', 2);
 define('_URL_SCHEME_NO_DOMAIN', 4);
 define('_URL_SCHEME_COLON_COORDINATES', 8);
 
-function common_url_schemes($filter=null)
+function common_url_schemes($filter = null)
 {
     // TODO: move these to $config
     $schemes = ['http'      => _URL_SCHEME_COLON_DOUBLE_SLASH,
@@ -1040,7 +1040,7 @@ function common_replace_urls_callback($text, $callback, $arg = null)
     '#ixu';
     //preg_match_all($regex,$text,$matches);
     //print_r($matches);
-    return preg_replace_callback($regex, curry('callback_helper', $callback, $arg), $text);
+    return preg_replace_callback($regex, callable_left_curry('callback_helper', $callback, $arg), $text);
 }
 
 /**
@@ -1054,11 +1054,11 @@ function common_replace_urls_callback($text, $callback, $arg = null)
  *
  * @access private
  */
-function callback_helper($matches, $callback, $arg=null)
+function callback_helper($matches, $callback, $arg = null)
 {
-    $url=$matches[1];
+    $url = $matches[1];
     $left = strpos($matches[0], $url);
-    $right = $left+strlen($url);
+    $right = $left + strlen($url);
 
     $groupSymbolSets=[
         [
@@ -1078,31 +1078,31 @@ function callback_helper($matches, $callback, $arg=null)
             'right'=>'>'
         ]
     ];
-    $cannotEndWith=['.','?',',','#'];
-    $original_url=$url;
+
+    $cannotEndWith = ['.','?',',','#'];
     do {
-        $original_url=$url;
+        $original_url = $url;
         foreach ($groupSymbolSets as $groupSymbolSet) {
-            if (substr($url, -1)==$groupSymbolSet['right']) {
+            if (substr($url, -1) == $groupSymbolSet['right']) {
                 $group_left_count = substr_count($url, $groupSymbolSet['left']);
                 $group_right_count = substr_count($url, $groupSymbolSet['right']);
-                if ($group_left_count<$group_right_count) {
-                    $right-=1;
-                    $url=substr($url, 0, -1);
+                if ($group_left_count < $group_right_count) {
+                    $right -= 1;
+                    $url = substr($url, 0, -1);
                 }
             }
         }
         if (in_array(substr($url, -1), $cannotEndWith)) {
-            $right-=1;
+            $right -= 1;
             $url=substr($url, 0, -1);
         }
-    } while ($original_url!=$url);
+    } while ($original_url != $url);
 
     $result = call_user_func_array($callback, [$url, $arg]);
     return substr($matches[0], 0, $left) . $result . substr($matches[0], $right);
 }
 
-require_once INSTALLDIR . "/lib/curry.php";
+require_once INSTALLDIR . "/lib/callable_left_curry.php";
 
 function common_linkify($url)
 {
index 6e776e41b4f09cd8cc464c886e0e742f65746d8e..2722a54fc5c1cf5ea77614bdd90298918c9ce667 100644 (file)
@@ -20,7 +20,7 @@ class CurryTest extends PHPUnit_Framework_TestCase
     public function testProduction($callback, $curry_params, $call_params, $expected)
     {
         $params = array_merge(array($callback), $curry_params);
-        $curried = call_user_func_array('curry', $params);
+        $curried = call_user_func_array('callable_left_curry', $params);
         $result = call_user_func_array($curried, $call_params);
         $this->assertEquals($expected, $result);
     }
index 8afc77cf8e0ea6aed9d005a53ad0292b3ea1f1ee..cbd741d8aab14e811378b2b5dc967cc2dfd60ffc 100644 (file)
@@ -379,6 +379,37 @@ return array(
     'HTMLPurifier_VarParser_Flexible' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php',
     'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
     'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
+    'Hoa\\Consistency\\Autoloader' => $vendorDir . '/hoa/consistency/Autoloader.php',
+    'Hoa\\Consistency\\Consistency' => $vendorDir . '/hoa/consistency/Consistency.php',
+    'Hoa\\Consistency\\Exception' => $vendorDir . '/hoa/consistency/Exception.php',
+    'Hoa\\Consistency\\Test\\Unit\\Autoloader' => $vendorDir . '/hoa/consistency/Test/Unit/Autoloader.php',
+    'Hoa\\Consistency\\Test\\Unit\\Consistency' => $vendorDir . '/hoa/consistency/Test/Unit/Consistency.php',
+    'Hoa\\Consistency\\Test\\Unit\\Exception' => $vendorDir . '/hoa/consistency/Test/Unit/Exception.php',
+    'Hoa\\Consistency\\Test\\Unit\\Xcallable' => $vendorDir . '/hoa/consistency/Test/Unit/Xcallable.php',
+    'Hoa\\Consistency\\Xcallable' => $vendorDir . '/hoa/consistency/Xcallable.php',
+    'Hoa\\Event\\Bucket' => $vendorDir . '/hoa/event/Bucket.php',
+    'Hoa\\Event\\Event' => $vendorDir . '/hoa/event/Event.php',
+    'Hoa\\Event\\Exception' => $vendorDir . '/hoa/event/Exception.php',
+    'Hoa\\Event\\Listenable' => $vendorDir . '/hoa/event/Listenable.php',
+    'Hoa\\Event\\Listener' => $vendorDir . '/hoa/event/Listener.php',
+    'Hoa\\Event\\Listens' => $vendorDir . '/hoa/event/Listens.php',
+    'Hoa\\Event\\Source' => $vendorDir . '/hoa/event/Source.php',
+    'Hoa\\Event\\Test\\Unit\\Bucket' => $vendorDir . '/hoa/event/Test/Unit/Bucket.php',
+    'Hoa\\Event\\Test\\Unit\\Event' => $vendorDir . '/hoa/event/Test/Unit/Event.php',
+    'Hoa\\Event\\Test\\Unit\\Exception' => $vendorDir . '/hoa/event/Test/Unit/Exception.php',
+    'Hoa\\Event\\Test\\Unit\\Listenable' => $vendorDir . '/hoa/event/Test/Unit/Listenable.php',
+    'Hoa\\Event\\Test\\Unit\\Listener' => $vendorDir . '/hoa/event/Test/Unit/Listener.php',
+    'Hoa\\Event\\Test\\Unit\\Listens' => $vendorDir . '/hoa/event/Test/Unit/Listens.php',
+    'Hoa\\Event\\Test\\Unit\\Source' => $vendorDir . '/hoa/event/Test/Unit/Source.php',
+    'Hoa\\Event\\Test\\Unit\\_Listenable' => $vendorDir . '/hoa/event/Test/Unit/Listens.php',
+    'Hoa\\Exception\\Error' => $vendorDir . '/hoa/exception/Error.php',
+    'Hoa\\Exception\\Exception' => $vendorDir . '/hoa/exception/Exception.php',
+    'Hoa\\Exception\\Group' => $vendorDir . '/hoa/exception/Group.php',
+    'Hoa\\Exception\\Idle' => $vendorDir . '/hoa/exception/Idle.php',
+    'Hoa\\Exception\\Test\\Unit\\Error' => $vendorDir . '/hoa/exception/Test/Unit/Error.php',
+    'Hoa\\Exception\\Test\\Unit\\Exception' => $vendorDir . '/hoa/exception/Test/Unit/Exception.php',
+    'Hoa\\Exception\\Test\\Unit\\Group' => $vendorDir . '/hoa/exception/Test/Unit/Group.php',
+    'Hoa\\Exception\\Test\\Unit\\Idle' => $vendorDir . '/hoa/exception/Test/Unit/Idle.php',
     'Masterminds\\HTML5' => $vendorDir . '/masterminds/html5/src/HTML5.php',
     'Masterminds\\HTML5\\Elements' => $vendorDir . '/masterminds/html5/src/HTML5/Elements.php',
     'Masterminds\\HTML5\\Entities' => $vendorDir . '/masterminds/html5/src/HTML5/Entities.php',
index 0698628c178e4e0b501bd5a65a276b92259cac63..d7eeeb8bbc9e2c5445ca8177fa74b34e559a75e5 100644 (file)
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'e88992873b7765f9b5710cab95ba5dd7' => $vendorDir . '/hoa/consistency/Prelude.php',
     '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
     '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
     '757772e28a0943a9afe83def8db95bdf' => $vendorDir . '/mf2/mf2/Mf2/Parser.php',
index de5192bb9177aeae7c7f9558490cc40ea3f5e08e..14af1954fbd5b79e5ea1525121cd09a7ecf8f8ee 100644 (file)
@@ -12,4 +12,7 @@ return array(
     'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
     'Michelf\\' => array($vendorDir . '/michelf/php-markdown/Michelf'),
     'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'),
+    'Hoa\\Exception\\' => array($vendorDir . '/hoa/exception'),
+    'Hoa\\Event\\' => array($vendorDir . '/hoa/event'),
+    'Hoa\\Consistency\\' => array($vendorDir . '/hoa/consistency'),
 );
index d560ecb13be5217264e63a0236cb82d353167d61..4f558716473ff833331f20736decac0afc512aa5 100644 (file)
@@ -7,6 +7,7 @@ namespace Composer\Autoload;
 class ComposerStaticInit444c3f31864f68a3f466e2c19837e185
 {
     public static $files = array (
+        'e88992873b7765f9b5710cab95ba5dd7' => __DIR__ . '/..' . '/hoa/consistency/Prelude.php',
         '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
         '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
         '757772e28a0943a9afe83def8db95bdf' => __DIR__ . '/..' . '/mf2/mf2/Mf2/Parser.php',
@@ -35,6 +36,12 @@ class ComposerStaticInit444c3f31864f68a3f466e2c19837e185
             'Michelf\\' => 8,
             'Masterminds\\' => 12,
         ),
+        'H' => 
+        array (
+            'Hoa\\Exception\\' => 14,
+            'Hoa\\Event\\' => 10,
+            'Hoa\\Consistency\\' => 16,
+        ),
     );
 
     public static $prefixDirsPsr4 = array (
@@ -62,6 +69,18 @@ class ComposerStaticInit444c3f31864f68a3f466e2c19837e185
         array (
             0 => __DIR__ . '/..' . '/masterminds/html5/src',
         ),
+        'Hoa\\Exception\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/hoa/exception',
+        ),
+        'Hoa\\Event\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/hoa/event',
+        ),
+        'Hoa\\Consistency\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/hoa/consistency',
+        ),
     );
 
     public static $prefixesPsr0 = array (
@@ -448,6 +467,37 @@ class ComposerStaticInit444c3f31864f68a3f466e2c19837e185
         'HTMLPurifier_VarParser_Flexible' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php',
         'HTMLPurifier_VarParser_Native' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
         'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
+        'Hoa\\Consistency\\Autoloader' => __DIR__ . '/..' . '/hoa/consistency/Autoloader.php',
+        'Hoa\\Consistency\\Consistency' => __DIR__ . '/..' . '/hoa/consistency/Consistency.php',
+        'Hoa\\Consistency\\Exception' => __DIR__ . '/..' . '/hoa/consistency/Exception.php',
+        'Hoa\\Consistency\\Test\\Unit\\Autoloader' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Autoloader.php',
+        'Hoa\\Consistency\\Test\\Unit\\Consistency' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Consistency.php',
+        'Hoa\\Consistency\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Exception.php',
+        'Hoa\\Consistency\\Test\\Unit\\Xcallable' => __DIR__ . '/..' . '/hoa/consistency/Test/Unit/Xcallable.php',
+        'Hoa\\Consistency\\Xcallable' => __DIR__ . '/..' . '/hoa/consistency/Xcallable.php',
+        'Hoa\\Event\\Bucket' => __DIR__ . '/..' . '/hoa/event/Bucket.php',
+        'Hoa\\Event\\Event' => __DIR__ . '/..' . '/hoa/event/Event.php',
+        'Hoa\\Event\\Exception' => __DIR__ . '/..' . '/hoa/event/Exception.php',
+        'Hoa\\Event\\Listenable' => __DIR__ . '/..' . '/hoa/event/Listenable.php',
+        'Hoa\\Event\\Listener' => __DIR__ . '/..' . '/hoa/event/Listener.php',
+        'Hoa\\Event\\Listens' => __DIR__ . '/..' . '/hoa/event/Listens.php',
+        'Hoa\\Event\\Source' => __DIR__ . '/..' . '/hoa/event/Source.php',
+        'Hoa\\Event\\Test\\Unit\\Bucket' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Bucket.php',
+        'Hoa\\Event\\Test\\Unit\\Event' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Event.php',
+        'Hoa\\Event\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Exception.php',
+        'Hoa\\Event\\Test\\Unit\\Listenable' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listenable.php',
+        'Hoa\\Event\\Test\\Unit\\Listener' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listener.php',
+        'Hoa\\Event\\Test\\Unit\\Listens' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listens.php',
+        'Hoa\\Event\\Test\\Unit\\Source' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Source.php',
+        'Hoa\\Event\\Test\\Unit\\_Listenable' => __DIR__ . '/..' . '/hoa/event/Test/Unit/Listens.php',
+        'Hoa\\Exception\\Error' => __DIR__ . '/..' . '/hoa/exception/Error.php',
+        'Hoa\\Exception\\Exception' => __DIR__ . '/..' . '/hoa/exception/Exception.php',
+        'Hoa\\Exception\\Group' => __DIR__ . '/..' . '/hoa/exception/Group.php',
+        'Hoa\\Exception\\Idle' => __DIR__ . '/..' . '/hoa/exception/Idle.php',
+        'Hoa\\Exception\\Test\\Unit\\Error' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Error.php',
+        'Hoa\\Exception\\Test\\Unit\\Exception' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Exception.php',
+        'Hoa\\Exception\\Test\\Unit\\Group' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Group.php',
+        'Hoa\\Exception\\Test\\Unit\\Idle' => __DIR__ . '/..' . '/hoa/exception/Test/Unit/Idle.php',
         'Masterminds\\HTML5' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5.php',
         'Masterminds\\HTML5\\Elements' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Elements.php',
         'Masterminds\\HTML5\\Entities' => __DIR__ . '/..' . '/masterminds/html5/src/HTML5/Entities.php',
index 34b0a044c4f3d95ff856f8a2670f25124e51856c..e47ff3faedaa95c703ce502b59d677a05041cf5e 100644 (file)
             "html"
         ]
     },
+    {
+        "name": "hoa/consistency",
+        "version": "1.17.05.02",
+        "version_normalized": "1.17.05.02",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/hoaproject/Consistency.git",
+            "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f",
+            "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f",
+            "shasum": ""
+        },
+        "require": {
+            "hoa/exception": "~1.0",
+            "php": ">=5.5.0"
+        },
+        "require-dev": {
+            "hoa/stream": "~1.0",
+            "hoa/test": "~2.0"
+        },
+        "time": "2017-05-02T12:18:12+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Hoa\\Consistency\\": "."
+            },
+            "files": [
+                "Prelude.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD-3-Clause"
+        ],
+        "authors": [
+            {
+                "name": "Ivan Enderlin",
+                "email": "ivan.enderlin@hoa-project.net"
+            },
+            {
+                "name": "Hoa community",
+                "homepage": "https://hoa-project.net/"
+            }
+        ],
+        "description": "The Hoa\\Consistency library.",
+        "homepage": "https://hoa-project.net/",
+        "keywords": [
+            "autoloader",
+            "callable",
+            "consistency",
+            "entity",
+            "flex",
+            "keyword",
+            "library"
+        ]
+    },
+    {
+        "name": "hoa/event",
+        "version": "1.17.01.13",
+        "version_normalized": "1.17.01.13",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/hoaproject/Event.git",
+            "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54",
+            "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54",
+            "shasum": ""
+        },
+        "require": {
+            "hoa/consistency": "~1.0",
+            "hoa/exception": "~1.0"
+        },
+        "require-dev": {
+            "hoa/test": "~2.0"
+        },
+        "time": "2017-01-13T15:30:50+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Hoa\\Event\\": "."
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD-3-Clause"
+        ],
+        "authors": [
+            {
+                "name": "Ivan Enderlin",
+                "email": "ivan.enderlin@hoa-project.net"
+            },
+            {
+                "name": "Hoa community",
+                "homepage": "https://hoa-project.net/"
+            }
+        ],
+        "description": "The Hoa\\Event library.",
+        "homepage": "https://hoa-project.net/",
+        "keywords": [
+            "event",
+            "library",
+            "listener",
+            "observer"
+        ]
+    },
+    {
+        "name": "hoa/exception",
+        "version": "1.17.01.16",
+        "version_normalized": "1.17.01.16",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/hoaproject/Exception.git",
+            "reference": "091727d46420a3d7468ef0595651488bfc3a458f"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f",
+            "reference": "091727d46420a3d7468ef0595651488bfc3a458f",
+            "shasum": ""
+        },
+        "require": {
+            "hoa/consistency": "~1.0",
+            "hoa/event": "~1.0"
+        },
+        "require-dev": {
+            "hoa/test": "~2.0"
+        },
+        "time": "2017-01-16T07:53:27+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Hoa\\Exception\\": "."
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD-3-Clause"
+        ],
+        "authors": [
+            {
+                "name": "Ivan Enderlin",
+                "email": "ivan.enderlin@hoa-project.net"
+            },
+            {
+                "name": "Hoa community",
+                "homepage": "https://hoa-project.net/"
+            }
+        ],
+        "description": "The Hoa\\Exception library.",
+        "homepage": "https://hoa-project.net/",
+        "keywords": [
+            "exception",
+            "library"
+        ]
+    },
     {
         "name": "masterminds/html5",
         "version": "2.6.0",
diff --git a/vendor/hoa/consistency/.State b/vendor/hoa/consistency/.State
new file mode 100644 (file)
index 0000000..a604de4
--- /dev/null
@@ -0,0 +1 @@
+finalized
diff --git a/vendor/hoa/consistency/.gitignore b/vendor/hoa/consistency/.gitignore
new file mode 100644 (file)
index 0000000..4fbb073
--- /dev/null
@@ -0,0 +1,2 @@
+/vendor/
+/composer.lock
diff --git a/vendor/hoa/consistency/.travis.yml b/vendor/hoa/consistency/.travis.yml
new file mode 100644 (file)
index 0000000..b44d944
--- /dev/null
@@ -0,0 +1,57 @@
+language: php
+
+matrix:
+  include:
+    - php: 5.5
+    - php: 5.6
+    - php: 7.0
+    - php: 7.1
+      env:
+        - ENABLE_XDEBUG=true
+    - php: 7.1
+      env:
+        - ENABLE_DEVTOOLS=true
+    - php: nightly
+    - php: hhvm-3.12
+      sudo: required
+      dist: trusty
+      group: edge
+    - php: hhvm
+      sudo: required
+      dist: trusty
+      group: edge
+  allow_failures:
+    - php: nightly
+    - php: hhvm-3.12
+    - php: hhvm
+  fast_finish: true
+
+os:
+  - linux
+
+notifications:
+  irc: "chat.freenode.net#hoaproject"
+
+sudo: false
+
+env:
+  global:
+    - secure: "AAAAB3NzaC1yc2EAAAADAQABAAACAQDIf0Rf76Hhkflz5b9UzWjOjk4UlMU5ySk0VY3B4WdHDLWMMK7fBp1Aj9qXWEDwkuX/NbQP1gB8jQNo7i5uZEOfu7Mn2svPkBBtnmKmaJhk90xypM4lcpcdPi4e8kXUgkriNQLQ2bRe1qZIeF115FkuIvActq7iWKY1TVSZbO54cDKMifDZfH09cf4vpwrZJqwZG6PUnUcCYijgDy99HtfRvzf9xalO4yWm55ZEbJ/VNTHlq1EhK73QLdHC7MO+OQFcd5wEyMbNxBj/bDn/udgb0HsrDijComTg/oTdQJMspYDQYV3ZYvpGozTTCVQrVTYYTP9RCNstgJLHDv9fZZW6yRlw4yNsT7jIQRLs/7awTxOAvRlxqaxk0//ECVNhDgawVtlbEIKrqnM1N7QTm0gjE0HkWEzxE0QbgoZqlLFD6qCp6WVvIT3uGY/i4TkVy78wf3/fzCKbrf72kYSbxIOCxVtptOmrgAblNEpiA/uZ9IofR2p2iwiVY1xF/mzxV2M4zCw6WASrlDhkaL0IncEdRtBuV2WTpixmtjmNkE9h/90kzb5cKExU786gZmvyflYvqlNlcMo3dNsDnROjQCAUXGBw5+risdqTT295BGmlEdZUtcf0c6/zEGhR8B7CktWYLSgOL5mpGMVNEBzyzEwnIiWCvI3pGgoV3Z9UzSJWKQ=="
+
+cache:
+  directories:
+    - vendor/
+
+before_script:
+  - export PATH="$PATH:$HOME/.composer/vendor/bin"
+  - if [[ ! $ENABLE_XDEBUG ]]; then
+      phpenv config-rm xdebug.ini || echo "ext-xdebug is not available, cannot remove it.";
+    fi
+
+script:
+  - composer install
+  - vendor/bin/hoa test:run
+  - if [[ $ENABLE_DEVTOOLS ]]; then
+      composer global require friendsofphp/php-cs-fixer;
+      vendor/bin/hoa devtools:cs --diff --dry-run .;
+    fi
diff --git a/vendor/hoa/consistency/Autoloader.php b/vendor/hoa/consistency/Autoloader.php
new file mode 100644 (file)
index 0000000..76f8e6c
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency;
+
+/**
+ * Class Hoa\Consistency\Autoloader.
+ *
+ * This class is a PSR-4 compliant autoloader.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Autoloader
+{
+    /**
+     * Namespace prefixes to base directories.
+     *
+     * @var array
+     */
+    protected $_namespacePrefixesToBaseDirectories = [];
+
+
+
+    /**
+     * Add a base directory for a namespace prefix.
+     *
+     * @param   string  $prefix           Namespace prefix.
+     * @param   string  $baseDirectory    Base directory for this prefix.
+     * @param   bool    $prepend          Whether the prefix is prepended or
+     *                                    appended to the prefix' stack.
+     * @return  void
+     */
+    public function addNamespace($prefix, $baseDirectory, $prepend = false)
+    {
+        $prefix        = trim($prefix, '\\') . '\\';
+        $baseDirectory = rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+
+        if (false === isset($this->_namespacePrefixesToBaseDirectories[$prefix])) {
+            $this->_namespacePrefixesToBaseDirectories[$prefix] = [];
+        }
+
+        if (true === $prepend) {
+            array_unshift(
+                $this->_namespacePrefixesToBaseDirectories[$prefix],
+                $baseDirectory
+            );
+        } else {
+            array_push(
+                $this->_namespacePrefixesToBaseDirectories[$prefix],
+                $baseDirectory
+            );
+        }
+
+        return;
+    }
+
+    /**
+     * Try to load the entity file for a given entity name.
+     *
+     * @param   string  $entity    Entity name to load.
+     * @return  bool
+     */
+    public function load($entity)
+    {
+        $entityPrefix     = $entity;
+        $hasBaseDirectory = false;
+
+        while (false !== $pos = strrpos($entityPrefix, '\\')) {
+            $currentEntityPrefix = substr($entity, 0, $pos + 1);
+            $entityPrefix        = rtrim($currentEntityPrefix, '\\');
+            $entitySuffix        = substr($entity, $pos + 1);
+            $entitySuffixAsPath  = str_replace('\\', '/', $entitySuffix);
+
+            if (false === $this->hasBaseDirectory($currentEntityPrefix)) {
+                continue;
+            }
+
+            $hasBaseDirectory = true;
+
+            foreach ($this->getBaseDirectories($currentEntityPrefix) as $baseDirectory) {
+                $file = $baseDirectory . $entitySuffixAsPath . '.php';
+
+                if (false !== $this->requireFile($file)) {
+                    return $file;
+                }
+            }
+        }
+
+        if (true    === $hasBaseDirectory &&
+            $entity === Consistency::getEntityShortestName($entity) &&
+            false   !== $pos = strrpos($entity, '\\')) {
+            return $this->runAutoloaderStack(
+                $entity . '\\' . substr($entity, $pos + 1)
+            );
+        }
+
+        return null;
+    }
+
+    /**
+     * Require a file if exists.
+     *
+     * @param   string  $filename    File name.
+     * @return  bool
+     */
+    public function requireFile($filename)
+    {
+        if (false === file_exists($filename)) {
+            return false;
+        }
+
+        require $filename;
+
+        return true;
+    }
+
+    /**
+     * Check whether at least one base directory exists for a namespace prefix.
+     *
+     * @param   string  $namespacePrefix    Namespace prefix.
+     * @return  bool
+     */
+    public function hasBaseDirectory($namespacePrefix)
+    {
+        return isset($this->_namespacePrefixesToBaseDirectories[$namespacePrefix]);
+    }
+
+    /**
+     * Get declared base directories for a namespace prefix.
+     *
+     * @param   string  $namespacePrefix    Namespace prefix.
+     * @return  array
+     */
+    public function getBaseDirectories($namespacePrefix)
+    {
+        if (false === $this->hasBaseDirectory($namespacePrefix)) {
+            return [];
+        }
+
+        return $this->_namespacePrefixesToBaseDirectories[$namespacePrefix];
+    }
+
+    /**
+     * Get loaded classes.
+     *
+     * @return  array
+     */
+    public static function getLoadedClasses()
+    {
+        return get_declared_classes();
+    }
+
+    /**
+     * Run the entire autoloader stack with a specific entity.
+     *
+     * @param   string  $entity    Entity name to load.
+     * @return  void
+     */
+    public function runAutoloaderStack($entity)
+    {
+        return spl_autoload_call($entity);
+    }
+
+    /**
+     * Register the autoloader.
+     *
+     * @param   bool  $prepend    Prepend this autoloader to the stack or not.
+     * @return  bool
+     */
+    public function register($prepend = false)
+    {
+        return spl_autoload_register([$this, 'load'], true, $prepend);
+    }
+
+    /**
+     * Unregister the autoloader.
+     *
+     * @return  bool
+     */
+    public function unregister()
+    {
+        return spl_autoload_unregister([$this, 'load']);
+    }
+
+    /**
+     * Get all registered autoloaders (not only from this library).
+     *
+     * @return  array
+     */
+    public function getRegisteredAutoloaders()
+    {
+        return spl_autoload_functions();
+    }
+
+    /**
+     * Dynamic new, a simple factory.
+     * It loads and constructs a class, with provided arguments.
+     *
+     * @param   bool     $classname    Classname.
+     * @param   array    $arguments    Arguments for the constructor.
+     * @return  object
+     */
+    public static function dnew($classname, array $arguments = [])
+    {
+        $classname = ltrim($classname, '\\');
+
+        if (false === Consistency::entityExists($classname, false)) {
+            spl_autoload_call($classname);
+        }
+
+        $class = new \ReflectionClass($classname);
+
+        if (empty($arguments) || false === $class->hasMethod('__construct')) {
+            return $class->newInstance();
+        }
+
+        return $class->newInstanceArgs($arguments);
+    }
+}
+
+/**
+ * Autoloader.
+ */
+$autoloader = new Autoloader();
+$autoloader->addNamespace('Hoa', dirname(__DIR__));
+$autoloader->register();
diff --git a/vendor/hoa/consistency/CHANGELOG.md b/vendor/hoa/consistency/CHANGELOG.md
new file mode 100644 (file)
index 0000000..21067ad
--- /dev/null
@@ -0,0 +1,51 @@
+# 1.17.05.02
+
+  * CI: Set up Travis. (Ivan Enderlin, 2017-03-08T09:52:17+01:00)
+  * Prelude: Remove the `(unset)` cast. (Ivan Enderlin, 2017-03-07T16:55:13+01:00)
+
+# 1.17.01.10
+
+  * Quality: Happy new year! (Alexis von Glasow, 2017-01-09T21:38:10+01:00)
+  * Documentation: New `README.md` file. (Ivan Enderlin, 2016-10-19T16:27:31+02:00)
+  * Documentation: Fix `docs` and `source` links. (Ivan Enderlin, 2016-10-05T20:26:20+02:00)
+  * Documentation: Update `support` properties. (Ivan Enderlin, 2016-10-05T15:56:01+02:00)
+  * Consistency: `void` is a reserved keyword now. (Ivan Enderlin, 2016-09-02T11:06:18+02:00)
+  * Consistency: Remove `trait_exists` polyfill. (Ivan Enderlin, 2016-08-23T17:26:07+02:00)
+
+# 1.16.03.03
+
+  * Add `STREAM_CRYPTO_METHOD_*` constants on PHP 5.5. (Metalaka, 2016-02-29T21:10:14+01:00)
+  * Composer: Fix `hoa/stream` dependency. (Ivan Enderlin, 2016-03-03T10:13:50+01:00)
+
+# 1.16.01.14
+
+  * Test: Write cases for flex entity in autoloader. (Ivan Enderlin, 2016-01-14T10:45:08+01:00)
+  * Autoloader: Restrict loads to mapped entities. (Ivan Enderlin, 2016-01-14T10:38:21+01:00)
+
+# 1.16.01.11
+
+  * Quality: Drop PHP5.4. (Ivan Enderlin, 2016-01-11T09:15:26+01:00)
+  * Quality: Run devtools:cs. (Ivan Enderlin, 2016-01-09T08:58:31+01:00)
+  * Core: Remove `Hoa\Core`. (Ivan Enderlin, 2016-01-09T08:03:33+01:00)
+
+# 0.16.01.06
+
+  * Prelude: Introduce the prelude/preamble! (Ivan Enderlin, 2015-12-09T08:34:16+01:00)
+  * Consistency: Import last methods from `Hoa\Core`. (Ivan Enderlin, 2015-12-09T08:24:02+01:00)
+  * Quality: Fix CS. (Ivan Enderlin, 2015-12-09T06:43:22+01:00)
+  * Add a `.gitignore` file. (Metalaka, 2015-12-03T13:21:11+01:00)
+  * Autoloader: Propagate unknown entity on the stack. (Ivan Enderlin, 2015-12-03T11:04:57+01:00)
+  * Autoloader: Auto-register to support flex entity. (Ivan Enderlin, 2015-12-03T10:01:23+01:00)
+  * Composer: Force some files to load. (Ivan Enderlin, 2015-12-03T08:15:55+01:00)
+  * Test: Simplify `case_register`. (Ivan Enderlin, 2015-12-03T08:15:19+01:00)
+  * Consistency: Use a strict equality check on trait. (Ivan Enderlin, 2015-12-02T17:11:50+01:00)
+  * README: First draft. (Ivan Enderlin, 2015-12-02T08:40:34+01:00)
+  * Documentation: Update API documentation. (Ivan Enderlin, 2015-12-02T08:37:58+01:00)
+  * Autoloader: Support flex entities. (Ivan Enderlin, 2015-12-02T08:18:39+01:00)
+  * Test: Write test suite of `…nsistency\Autoloader`. (Ivan Enderlin, 2015-12-01T08:42:30+01:00)
+  * Test: Write test suite of `…sistency\Consistency`. (Ivan Enderlin, 2015-11-25T22:10:30+01:00)
+  * Test: Write test suite of `…onsistency\Xcallable`. (Ivan Enderlin, 2015-11-25T08:45:59+01:00)
+  * Test: Write test suite of `…onsistency\Exception`. (Ivan Enderlin, 2015-11-24T16:59:18+01:00)
+  * Split from `Hoa\Core`. (Ivan Enderlin, 2015-11-23T23:08:19+01:00)
+
+(first snapshot)
diff --git a/vendor/hoa/consistency/Consistency.php b/vendor/hoa/consistency/Consistency.php
new file mode 100644 (file)
index 0000000..d1da5a6
--- /dev/null
@@ -0,0 +1,363 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency
+{
+
+/**
+ * Class Hoa\Consistency\Consistency.
+ *
+ * This class is a collection of tools to ensure foreward and backward
+ * compatibility.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Consistency
+{
+    /**
+     * Check if an entity exists (class, interface, trait…).
+     *
+     * @param   string  $entityName    Entity name.
+     * @param   bool    $autoloader    Run autoloader if necessary.
+     * @return  bool
+     */
+    public static function entityExists($entityName, $autoloader = false)
+    {
+        return
+            class_exists($entityName, $autoloader) ||
+            interface_exists($entityName, false)   ||
+            trait_exists($entityName, false);
+    }
+
+    /**
+     * Get the shortest name for an entity.
+     *
+     * @param   string  $entityName    Entity name.
+     * @return  string
+     */
+    public static function getEntityShortestName($entityName)
+    {
+        $parts = explode('\\', $entityName);
+        $count = count($parts);
+
+        if (1 >= $count) {
+            return $entityName;
+        }
+
+        if ($parts[$count - 2] === $parts[$count - 1]) {
+            return implode('\\', array_slice($parts, 0, -1));
+        }
+
+        return $entityName;
+    }
+
+    /**
+     * Declare a flex entity (for nested library).
+     *
+     * @param   string  $entityName    Entity name.
+     * @return  bool
+     */
+    public static function flexEntity($entityName)
+    {
+        return class_alias(
+            $entityName,
+            static::getEntityShortestName($entityName),
+            false
+        );
+    }
+
+    /**
+     * Whether a word is reserved or not.
+     *
+     * @param   string  $word    Word.
+     * @return  bool
+     */
+    public static function isKeyword($word)
+    {
+        static $_list = [
+            // PHP keywords.
+            '__halt_compiler',
+            'abstract',
+            'and',
+            'array',
+            'as',
+            'bool',
+            'break',
+            'callable',
+            'case',
+            'catch',
+            'class',
+            'clone',
+            'const',
+            'continue',
+            'declare',
+            'default',
+            'die',
+            'do',
+            'echo',
+            'else',
+            'elseif',
+            'empty',
+            'enddeclare',
+            'endfor',
+            'endforeach',
+            'endif',
+            'endswitch',
+            'endwhile',
+            'eval',
+            'exit',
+            'extends',
+            'false',
+            'final',
+            'float',
+            'for',
+            'foreach',
+            'function',
+            'global',
+            'goto',
+            'if',
+            'implements',
+            'include',
+            'include_once',
+            'instanceof',
+            'insteadof',
+            'int',
+            'interface',
+            'isset',
+            'list',
+            'mixed',
+            'namespace',
+            'new',
+            'null',
+            'numeric',
+            'object',
+            'or',
+            'print',
+            'private',
+            'protected',
+            'public',
+            'require',
+            'require_once',
+            'resource',
+            'return',
+            'static',
+            'string',
+            'switch',
+            'throw',
+            'trait',
+            'true',
+            'try',
+            'unset',
+            'use',
+            'var',
+            'void',
+            'while',
+            'xor',
+            'yield',
+
+            // Compile-time constants.
+            '__class__',
+            '__dir__',
+            '__file__',
+            '__function__',
+            '__line__',
+            '__method__',
+            '__namespace__',
+            '__trait__'
+        ];
+
+        return in_array(strtolower($word), $_list);
+    }
+
+    /**
+     * Whether an ID is a valid PHP identifier.
+     *
+     * @param   string  $id    ID.
+     * @return  bool
+     */
+    public static function isIdentifier($id)
+    {
+        return 0 !== preg_match(
+            '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#',
+            $id
+        );
+    }
+
+    /**
+     * Register a register shutdown function.
+     * It may be analogous to a super static destructor.
+     *
+     * @param   callable  $callable    Callable.
+     * @return  bool
+     */
+    public static function registerShutdownFunction($callable)
+    {
+        return register_shutdown_function($callable);
+    }
+
+    /**
+     * Get PHP executable.
+     *
+     * @return  string
+     */
+    public static function getPHPBinary()
+    {
+        if (defined('PHP_BINARY')) {
+            return PHP_BINARY;
+        }
+
+        if (isset($_SERVER['_'])) {
+            return $_SERVER['_'];
+        }
+
+        foreach (['', '.exe'] as $extension) {
+            if (file_exists($_ = PHP_BINDIR . DS . 'php' . $extension)) {
+                return realpath($_);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Generate an Universal Unique Identifier (UUID).
+     *
+     * @return  string
+     */
+    public static function uuid()
+    {
+        return sprintf(
+            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+            mt_rand(0, 0xffff),
+            mt_rand(0, 0xffff),
+            mt_rand(0, 0xffff),
+            mt_rand(0, 0x0fff) | 0x4000,
+            mt_rand(0, 0x3fff) | 0x8000,
+            mt_rand(0, 0xffff),
+            mt_rand(0, 0xffff),
+            mt_rand(0, 0xffff)
+        );
+    }
+}
+
+}
+
+namespace
+{
+
+if (70000 > PHP_VERSION_ID && false === interface_exists('Throwable', false)) {
+    /**
+     * Implement a fake Throwable class, introduced in PHP7.0.
+     */
+    interface Throwable
+    {
+        public function getMessage();
+        public function getCode();
+        public function getFile();
+        public function getLine();
+        public function getTrace();
+        public function getPrevious();
+        public function getTraceAsString();
+        public function __toString();
+    }
+}
+
+/**
+ * Define TLSv* constants, introduced in PHP 5.5.
+ */
+if (50600 > PHP_VERSION_ID) {
+    $define = function ($constantName, $constantValue, $case = false) {
+        if (!defined($constantName)) {
+            return define($constantName, $constantValue, $case);
+        }
+
+        return false;
+    };
+
+    $define('STREAM_CRYPTO_METHOD_TLSv1_0_SERVER', 8);
+    $define('STREAM_CRYPTO_METHOD_TLSv1_1_SERVER', 16);
+    $define('STREAM_CRYPTO_METHOD_TLSv1_2_SERVER', 32);
+    $define('STREAM_CRYPTO_METHOD_ANY_SERVER', 62);
+
+    $define('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT', 9);
+    $define('STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT', 17);
+    $define('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT', 33);
+    $define('STREAM_CRYPTO_METHOD_ANY_CLIENT', 63);
+}
+
+if (!function_exists('curry')) {
+    /**
+     * Curry.
+     * Example:
+     *     $c = curry('str_replace', …, …, 'foobar');
+     *     var_dump($c('foo', 'baz')); // bazbar
+     *     $c = curry('str_replace', 'foo', 'baz', …);
+     *     var_dump($c('foobarbaz')); // bazbarbaz
+     * Nested curries also work:
+     *     $c1 = curry('str_replace', …, …, 'foobar');
+     *     $c2 = curry($c1, 'foo', …);
+     *     var_dump($c2('baz')); // bazbar
+     * Obviously, as the first argument is a callable, we can combine this with
+     * \Hoa\Consistency\Xcallable ;-).
+     * The “…” character is the HORIZONTAL ELLIPSIS Unicode character (Unicode:
+     * 2026, UTF-8: E2 80 A6).
+     *
+     * @param   mixed  $callable    Callable (two parts).
+     * @param   ...    ...          Arguments.
+     * @return  \Closure
+     */
+    function curry($callable)
+    {
+        $arguments = func_get_args();
+        array_shift($arguments);
+        $ii        = array_keys($arguments, …, true);
+
+        return function () use ($callable, $arguments, $ii) {
+            return call_user_func_array(
+                $callable,
+                array_replace($arguments, array_combine($ii, func_get_args()))
+            );
+        };
+    }
+}
+
+/**
+ * Flex entity.
+ */
+Hoa\Consistency\Consistency::flexEntity('Hoa\Consistency\Consistency');
+
+}
diff --git a/vendor/hoa/consistency/Exception.php b/vendor/hoa/consistency/Exception.php
new file mode 100644 (file)
index 0000000..c7ae2a3
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency;
+
+use Hoa\Exception as HoaException;
+
+/**
+ * Class \Hoa\Consistency\Exception.
+ *
+ * Extending the \Hoa\Exception\Exception class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends HoaException
+{
+}
diff --git a/vendor/hoa/consistency/Prelude.php b/vendor/hoa/consistency/Prelude.php
new file mode 100644 (file)
index 0000000..e7d8f77
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+if (false === defined('HOA')) {
+    define('HOA', true);
+}
+
+if (false === defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50400) {
+    throw new Exception(
+        'Hoa needs at least PHP5.4 to work; you have ' . phpversion() . '.'
+    );
+}
+
+require_once __DIR__ . DIRECTORY_SEPARATOR . 'Autoloader.php';
+require_once __DIR__ . DIRECTORY_SEPARATOR . 'Consistency.php';
+
+$define = function ($constantName, $constantValue, $case = false) {
+    if (!defined($constantName)) {
+        return define($constantName, $constantValue, $case);
+    }
+
+    return false;
+};
+
+$define('SUCCEED',        true);
+$define('FAILED',         false);
+$define('…',              '__hoa_core_fill');
+$define('DS',             DIRECTORY_SEPARATOR);
+$define('PS',             PATH_SEPARATOR);
+$define('ROOT_SEPARATOR', ';');
+$define('RS',             ROOT_SEPARATOR);
+$define('CRLF',           "\r\n");
+$define('OS_WIN',         defined('PHP_WINDOWS_VERSION_PLATFORM'));
+$define('S_64_BITS',      PHP_INT_SIZE == 8);
+$define('S_32_BITS',      !S_64_BITS);
+$define('PHP_INT_MIN',    ~PHP_INT_MAX);
+$define('PHP_FLOAT_MIN',  (float) PHP_INT_MIN);
+$define('PHP_FLOAT_MAX',  (float) PHP_INT_MAX);
+$define('π',              M_PI);
+$define('nil',            null);
+$define('_public',        1);
+$define('_protected',     2);
+$define('_private',       4);
+$define('_static',        8);
+$define('_abstract',      16);
+$define('_pure',          32);
+$define('_final',         64);
+$define('_dynamic',       ~_static);
+$define('_concrete',      ~_abstract);
+$define('_overridable',   ~_final);
+$define('WITH_COMPOSER',  class_exists('Composer\Autoload\ClassLoader', false) ||
+                          ('cli' === PHP_SAPI &&
+                          file_exists(__DIR__ . DS . '..' . DS . '..' . DS . 'autoload.php')));
+
+/**
+ * Alias of \Hoa\Consistency\Xcallable.
+ *
+ * @param   mixed   $call    First callable part.
+ * @param   mixed   $able    Second callable part (if needed).
+ * @return  mixed
+ */
+if (!function_exists('xcallable')) {
+    function xcallable($call, $able = '')
+    {
+        if ($call instanceof Hoa\Consistency\Xcallable) {
+            return $call;
+        }
+
+        return new Hoa\Consistency\Xcallable($call, $able);
+    }
+}
diff --git a/vendor/hoa/consistency/README.md b/vendor/hoa/consistency/README.md
new file mode 100644 (file)
index 0000000..d21790d
--- /dev/null
@@ -0,0 +1,275 @@
+<p align="center">
+  <img src="https://static.hoa-project.net/Image/Hoa.svg" alt="Hoa" width="250px" />
+</p>
+
+---
+
+<p align="center">
+  <a href="https://travis-ci.org/hoaproject/Consistency"><img src="https://img.shields.io/travis/hoaproject/Consistency/master.svg" alt="Build status" /></a>
+  <a href="https://coveralls.io/github/hoaproject/Consistency?branch=master"><img src="https://img.shields.io/coveralls/hoaproject/Consistency/master.svg" alt="Code coverage" /></a>
+  <a href="https://packagist.org/packages/hoa/consistency"><img src="https://img.shields.io/packagist/dt/hoa/consistency.svg" alt="Packagist" /></a>
+  <a href="https://hoa-project.net/LICENSE"><img src="https://img.shields.io/packagist/l/hoa/consistency.svg" alt="License" /></a>
+</p>
+<p align="center">
+  Hoa is a <strong>modular</strong>, <strong>extensible</strong> and
+  <strong>structured</strong> set of PHP libraries.<br />
+  Moreover, Hoa aims at being a bridge between industrial and research worlds.
+</p>
+
+# Hoa\Consistency
+
+[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
+[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
+[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Consistency)
+[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/consistency)
+
+This library provides a thin layer between PHP VMs and libraries to ensure
+consistency accross VM versions and library versions.
+
+[Learn more](https://central.hoa-project.net/Documentation/Library/Consistency).
+
+## Installation
+
+With [Composer](https://getcomposer.org/), to include this library into
+your dependencies, you need to
+require [`hoa/consistency`](https://packagist.org/packages/hoa/consistency):
+
+```sh
+$ composer require hoa/consistency '~1.0'
+```
+
+For more installation procedures, please read [the Source
+page](https://hoa-project.net/Source.html).
+
+## Testing
+
+Before running the test suites, the development dependencies must be installed:
+
+```sh
+$ composer install
+```
+
+Then, to run all the test suites:
+
+```sh
+$ vendor/bin/hoa test:run
+```
+
+For more information, please read the [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html).
+
+## Quick usage
+
+We propose a quick overview of how the consistency API ensures foreward and
+backward compatibility, also an overview of the [PSR-4
+autoloader](http://www.php-fig.org/psr/psr-4/) and the xcallable API.
+
+### Foreward and backward compatibility
+
+The `Hoa\Consistency\Consistency` class ensures foreward and backward
+compatibility.
+
+#### Example with keywords
+
+The `Hoa\Consistency\Consistency::isKeyword` checks whether a specific word is
+reserved by PHP or not. Let's say your current PHP version does not support the
+`callable` keyword or type declarations such as `int`, `float`, `string` etc.,
+the `isKeyword` method will tell you if they are reserved keywords: Not only
+for your current PHP version, but maybe in an incoming version.
+
+```php
+$isKeyword = Hoa\Consistency\Consistency::isKeyword('yield');
+```
+
+It avoids to write algorithms that might break in the future or for your users
+living on the edge.
+
+#### Example with identifiers
+
+PHP identifiers are defined by a regular expression. It might change in the
+future. To prevent breaking your algorithms, you can use the
+`Hoa\Consistency\Consistency::isIdentifier` method to check an identifier is
+correct regarding current PHP version:
+
+```php
+$isValidIdentifier = Hoa\Consistency\Consistency::isIdentifier('foo');
+```
+
+#### Flexible entities
+
+Flexible entities are very simple. If we declare `Foo\Bar\Bar` as a flexible
+entity, we will be able to access it with the `Foo\Bar\Bar` name or `Foo\Bar`.
+This is very useful if your architecture evolves but you want to keep the
+backward compatibility. For instance, it often happens that you create a
+`Foo\Bar\Exception` class in the `Foo/Bar/Exception.php` file. But after few
+versions, you realise other exceptions need to be introduced, so you need an
+`Exception` directory. In this case, `Foo\Bar\Exception` should move as
+`Foo\Bar\Exception\Exception`. If this latter is declared as a flexible entity,
+backward compatibility will be kept.
+
+```php
+Hoa\Consistency\Consistency::flexEntity('Foo\Bar\Exception\Exception');
+```
+
+Another example is the “entry-class” (informal naming).
+`Hoa\Consistency\Consistency` is a good example. This is more convenient to
+write `Hoa\Consistency` instead of `Hoa\Consistency\Consistency`. This is
+possible because this is a flexible entity.
+
+#### Throwable & co.
+
+The `Throwable` interface has been introduced to represent a whole new exception
+architecture in PHP. Thus, to be compatible with incoming PHP versions, you
+might want to use this interface in some cases. Hopefully, the `Throwable`
+interface will be created for you if it does not exists.
+
+```php
+try {
+    …
+} catch (Throwable $e) {
+    …
+}
+```
+
+### Autoloader
+
+`Hoa\Consistency\Autoloader` is a [PSR-4
+compatible](http://www.php-fig.org/psr/psr-4/) autoloader. It simply works as
+follows:
+  * `addNamespace` is used to map a namespace prefix to a directory,
+  * `register` is used to register the autoloader.
+
+The API also provides the `load` method to force the load of an entity,
+`unregister` to unregister the autoloader, `getRegisteredAutoloaders` to get
+a list of all registered autoloaders etc.
+
+For instance, to map the `Foo\Bar` namespace to the `Source/` directory:
+
+```php
+$autoloader = new Hoa\Consistency\Autoloader();
+$autoloader->addNamespace('Foo\Bar', 'Source');
+$autoloader->register();
+
+$baz = new Foo\Bar\Baz(); // automatically loaded!
+```
+
+### Xcallable
+
+Xcallables are “extended callables”. It is a unified API to invoke callables of
+any kinds, and also extends some Hoa's API (like
+[`Hoa\Event`](https://central.hoa-project.net/Resource/Library/Event)
+or
+[`Hoa\Stream`](https://central.hoa-project.net/Resource/Library/Stream)). It
+understands the following kinds:
+  * `'function'` as a string,
+  * `'class::method'` as a string,
+  * `'class', 'method'` as 2 string arguments,
+  * `$object, 'method'` as 2 arguments,
+  * `$object, ''` as 2 arguments, the “able” is unknown,
+  * `function (…) { … }` as a closure,
+  * `['class', 'method']` as an array of strings,
+  * `[$object, 'method']` as an array.
+
+To use it, simply instanciate the `Hoa\Consistency\Xcallable` class and use it
+as a function:
+
+```php
+$xcallable = new Hoa\Consistency\Xcallable('strtoupper');
+var_dump($xcallable('foo'));
+
+/**
+ * Will output:
+ *     string(3) "FOO"
+ */
+```
+
+The `Hoa\Consistency\Xcallable::distributeArguments` method invokes the callable
+but the arguments are passed as an array:
+
+```php
+$xcallable->distributeArguments(['foo']);
+```
+
+This is also possible to get a unique hash of the callable:
+
+```php
+var_dump($xcallable->getHash());
+
+/**
+ * Will output:
+ *     string(19) "function#strtoupper"
+ */
+```
+
+Finally, this is possible to get a reflection instance of the current callable
+(can be of kind [`ReflectionFunction`](http://php.net/ReflectionFunction),
+[`ReflectionClass`](http://php.net/ReflectionClass),
+[`ReflectionMethod`](http://php.net/ReflectionMethod) or
+[`ReflectionObject`](http://php.net/ReflectionObject)):
+
+```php
+var_dump($xcallable->getReflection());
+
+/**
+ * Will output:
+ *     object(ReflectionFunction)#42 (1) {
+ *       ["name"]=>
+ *       string(10) "strtoupper"
+ *     }
+ */
+```
+
+When the object is set but not the method, the latter will be deduced if
+possible. If the object is of kind
+[`Hoa\Stream`](http://central.hoa-project.net/Resource/Library/Stream), then
+according to the type of the arguments given to the callable, the
+`writeInteger`, `writeString`, `writeArray` etc. method will be used. If the
+argument is of kind `Hoa\Event\Bucket`, then the method name will be deduced
+based on the data contained inside the event bucket. This is very handy. For
+instance, the following example will work seamlessly:
+
+```php
+Hoa\Event\Event::getEvent('hoa://Event/Exception')
+    ->attach(new Hoa\File\Write('Exceptions.log'));
+```
+
+The `attach` method on `Hoa\Event\Event` transforms its argument as an
+xcallable. In this particular case, the method to call is unknown, we only have
+an object (of kind `Hoa\File\Write`). However, because this is a stream, the
+method will be deduced according to the data contained in the event bucket fired
+on the `hoa://Event/Exception` event channel.
+
+## Documentation
+
+The
+[hack book of `Hoa\Consistency`](https://central.hoa-project.net/Documentation/Library/Consistency)
+contains detailed information about how to use this library and how it works.
+
+To generate the documentation locally, execute the following commands:
+
+```sh
+$ composer require --dev hoa/devtools
+$ vendor/bin/hoa devtools:documentation --open
+```
+
+More documentation can be found on the project's website:
+[hoa-project.net](https://hoa-project.net/).
+
+## Getting help
+
+There are mainly two ways to get help:
+
+  * On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
+    IRC channel,
+  * On the forum at [users.hoa-project.net](https://users.hoa-project.net).
+
+## Contribution
+
+Do you want to contribute? Thanks! A detailed [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
+everything you need to know.
+
+## License
+
+Hoa is under the New BSD License (BSD-3-Clause). Please, see
+[`LICENSE`](https://hoa-project.net/LICENSE) for details.
diff --git a/vendor/hoa/consistency/Test/Unit/Autoloader.php b/vendor/hoa/consistency/Test/Unit/Autoloader.php
new file mode 100644 (file)
index 0000000..002983f
--- /dev/null
@@ -0,0 +1,342 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency\Test\Unit;
+
+use Hoa\Consistency\Autoloader as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Consistency\Test\Unit\Autoloader.
+ *
+ * Test suite of the autoloader.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Autoloader extends Test\Unit\Suite
+{
+    public function case_add_namespace_prepend()
+    {
+        $this
+            ->given(
+                $autoloader     = new SUT(),
+                $prefix         = 'Foo\Bar\\',
+                $baseDirectoryA = 'Source/Foo/Bar/',
+                $baseDirectoryB = 'Source/Foo/Bar/'
+            )
+            ->when(
+                $autoloader->addNamespace($prefix, $baseDirectoryA),
+                $result = $autoloader->addNamespace($prefix, $baseDirectoryB)
+            )
+            ->then
+                ->boolean($autoloader->hasBaseDirectory($prefix))
+                    ->isTrue()
+                ->array($autoloader->getBaseDirectories($prefix))
+                    ->isEqualTo([
+                        $baseDirectoryB,
+                        $baseDirectoryA
+                    ]);
+    }
+
+    public function case_add_namespace_append()
+    {
+        $this
+            ->given(
+                $autoloader     = new SUT(),
+                $prefix         = 'Foo\Bar\\',
+                $baseDirectoryA = 'Source/Foo/Bar/',
+                $baseDirectoryB = 'Source/Foo/Bar/'
+            )
+            ->when(
+                $autoloader->addNamespace($prefix, $baseDirectoryA),
+                $result = $autoloader->addNamespace($prefix, $baseDirectoryB)
+            )
+            ->then
+                ->boolean($autoloader->hasBaseDirectory($prefix))
+                    ->isTrue()
+                ->array($autoloader->getBaseDirectories($prefix))
+                    ->isEqualTo([
+                        $baseDirectoryA,
+                        $baseDirectoryB
+                    ]);
+    }
+
+    public function case_add_namespace_with_invalid_prefix()
+    {
+        $this
+            ->given(
+                $autoloader    = new SUT(),
+                $prefix        = '\\\\Foo\Bar',
+                $baseDirectory = 'Source/Foo/Bar/'
+            )
+            ->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
+            ->then
+                ->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
+                    ->isTrue()
+                ->array($autoloader->getBaseDirectories('Foo\Bar\\'))
+                    ->isEqualTo([$baseDirectory]);
+    }
+
+    public function case_add_namespace_with_invalid_base_directory()
+    {
+        $this
+            ->given(
+                $autoloader    = new SUT(),
+                $prefix        = 'Foo\Bar\\',
+                $baseDirectory = 'Source/Foo/Bar'
+            )
+            ->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
+            ->then
+                ->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
+                    ->isTrue()
+                ->array($autoloader->getBaseDirectories('Foo\Bar\\'))
+                    ->isEqualTo(['Source/Foo/Bar/']);
+    }
+
+    public function case_add_namespace_with_crazy_invalid_base_directory()
+    {
+        $this
+            ->given(
+                $autoloader    = new SUT(),
+                $prefix        = 'Foo\Bar\\',
+                $baseDirectory = 'Source/Foo/Bar/////'
+            )
+            ->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
+            ->then
+                ->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
+                    ->isTrue()
+                ->array($autoloader->getBaseDirectories('Foo\Bar\\'))
+                    ->isEqualTo(['Source/Foo/Bar/']);
+    }
+
+    public function case_load()
+    {
+        $this
+            ->given(
+                $autoloader = new \Mock\Hoa\Consistency\Autoloader(),
+                $autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/Bar/'),
+                $this->calling($autoloader)->requireFile = function ($file) {
+                    return $file;
+                }
+            )
+            ->when($result = $autoloader->load('Foo\Bar\Baz\Qux'))
+            ->then
+                ->string($result)
+                    ->isEqualTo('Source/Foo/Bar/Baz/Qux.php');
+    }
+
+    public function case_load_invalid_entity()
+    {
+        $this
+            ->given($autoloader = new SUT())
+            ->when($result = $autoloader->load('Foo'))
+            ->then
+                ->variable($result)
+                    ->isNull();
+    }
+
+    public function case_load_flex_entity()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $autoloader = new \Mock\Hoa\Consistency\Autoloader(),
+                $autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/'),
+                $this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called) {
+                    $called = true;
+                    $self
+                        ->string($entity)
+                            ->isEqualTo('Foo\Bar\Baz\Baz');
+
+                    return;
+                },
+                $autoloader->register()
+            )
+            ->when($result = $autoloader->load('Foo\Bar\Baz'))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_load_unmapped_flex_entity()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $autoloader = new \Mock\Hoa\Consistency\Autoloader(),
+                $this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called) {
+                    $called = true;
+
+                    return;
+                },
+                $autoloader->register()
+            )
+            ->when($result = $autoloader->load('Foo\Bar\Baz'))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->variable($called)
+                    ->isNull();
+    }
+
+    public function case_require_existing_file()
+    {
+        $this
+            ->given(
+                $autoloader = new SUT(),
+
+                $this->function->file_exists = true,
+
+                $constantName = 'HOA_TEST_' . uniqid(),
+                $filename     = 'hoa://Test/Vfs/Foo?type=file',
+
+                file_put_contents($filename, '<?php define("' . $constantName . '", "BAR");')
+            )
+            ->when($result = $autoloader->requireFile($filename))
+            ->then
+                ->boolean($result)
+                    ->isTrue()
+                ->string(constant($constantName))
+                    ->isEqualTo('BAR');
+    }
+
+    public function case_require_not_existing_file()
+    {
+        $this
+            ->given(
+                $autoloader                  = new SUT(),
+                $this->function->file_exists = false
+            )
+            ->when($result = $autoloader->requireFile('/hoa/flatland'))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_has_not_base_directory()
+    {
+        $this
+            ->given($autoloader = new SUT())
+            ->when($result = $autoloader->hasBaseDirectory('foo'))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_get_base_undeclared_namespace_prefix()
+    {
+        $this
+            ->given($autoloader = new SUT())
+            ->when($result = $autoloader->getBaseDirectories('foo'))
+            ->then
+                ->array($result)
+                    ->isEmpty();
+    }
+
+    public function case_dnew()
+    {
+        $this
+            ->given($classname = 'Hoa\Consistency\Autoloader')
+            ->when($result = SUT::dnew($classname))
+            ->then
+                ->object($result)
+                    ->isInstanceOf($classname);
+    }
+
+    public function case_dnew_unknown_class()
+    {
+        $this
+            ->given($this->function->spl_autoload_call = null)
+            ->exception(function () {
+                SUT::dnew('Foo');
+            })
+                ->isInstanceOf('ReflectionException');
+    }
+
+    public function case_get_loaded_classes()
+    {
+        $this
+            ->given(
+                $declaredClasses                      = get_declared_classes(),
+                $this->function->get_declared_classes = $declaredClasses
+            )
+            ->when($result = SUT::getLoadedClasses())
+            ->then
+                ->array($result)
+                    ->isEqualTo($declaredClasses);
+    }
+
+    public function case_register()
+    {
+        $self = $this;
+
+        $this
+            ->given($autoloader = new SUT())
+            ->when($result = $autoloader->register())
+            ->then
+                ->boolean($result)
+                    ->isTrue()
+                ->array($autoloader->getRegisteredAutoloaders())
+                    ->isEqualTo(spl_autoload_functions());
+    }
+
+    public function case_unregister()
+    {
+        $this
+            ->given(
+                $autoloader               = new SUT(),
+                $oldRegisteredAutoloaders = $autoloader->getRegisteredAutoloaders()
+            )
+            ->when($result = $autoloader->register())
+            ->then
+                ->boolean($result)
+                    ->isTrue()
+                ->integer(count($autoloader->getRegisteredAutoloaders()))
+                    ->isEqualTo(count($oldRegisteredAutoloaders) + 1)
+
+            ->when($result = $autoloader->unregister())
+            ->then
+                ->boolean($result)
+                    ->isTrue()
+                ->array($autoloader->getRegisteredAutoloaders())
+                    ->isEqualTo($oldRegisteredAutoloaders);
+    }
+}
diff --git a/vendor/hoa/consistency/Test/Unit/Consistency.php b/vendor/hoa/consistency/Test/Unit/Consistency.php
new file mode 100644 (file)
index 0000000..f923fc7
--- /dev/null
@@ -0,0 +1,325 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency\Test\Unit;
+
+use Hoa\Consistency\Consistency as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Consistency\Test\Unit\Consistency.
+ *
+ * Test suite of the consistency class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Consistency extends Test\Unit\Suite
+{
+    protected function _entity_exists_with_xxx($class, $interface, $trait)
+    {
+        $this
+            ->given(
+                $this->function->class_exists     = $class,
+                $this->function->interface_exists = $interface,
+                $this->function->trait_exists     = $trait
+            )
+            ->when($result = SUT::entityExists('foo'))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_entity_exists_with_class()
+    {
+        return $this->_entity_exists_with_xxx(true, false, false);
+    }
+
+    public function case_entity_exists_with_interface()
+    {
+        return $this->_entity_exists_with_xxx(false, true, false);
+    }
+
+    public function case_entity_exists_with_trait()
+    {
+        return $this->_entity_exists_with_xxx(false, false, true);
+    }
+
+    public function case_entity_does_not_exists()
+    {
+        $this
+            ->given(
+                $this->function->class_exists     = false,
+                $this->function->interface_exists = false,
+                $this->function->trait_exists     = false
+            )
+            ->when($result = SUT::entityExists('foo'))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_get_entity_shortest_name()
+    {
+        $this
+            ->when($result = SUT::getEntityShortestName('Foo\Bar\Bar'))
+            ->then
+                ->string($result)
+                    ->isEqualTo('Foo\Bar');
+    }
+
+    public function case_get_entity_shortest_name_with_already_the_shortest()
+    {
+        $this
+            ->when($result = SUT::getEntityShortestName('Foo\Bar'))
+            ->then
+                ->string($result)
+                    ->isEqualTo('Foo\Bar');
+    }
+
+    public function case_get_entity_shortest_name_with_no_namespace()
+    {
+        $this
+            ->when($result = SUT::getEntityShortestName('Foo'))
+            ->then
+                ->string($result)
+                    ->isEqualTo('Foo');
+    }
+
+    public function case_is_keyword()
+    {
+        $this
+            ->given(
+                $keywords = [
+                    '__HALT_COMPILER',
+                    'abstract',
+                    'and',
+                    'array',
+                    'as',
+                    'bool',
+                    'break',
+                    'callable',
+                    'case',
+                    'catch',
+                    'class',
+                    'clone',
+                    'const',
+                    'continue',
+                    'declare',
+                    'default',
+                    'die',
+                    'do',
+                    'echo',
+                    'else',
+                    'elseif',
+                    'empty',
+                    'enddeclare',
+                    'endfor',
+                    'endforeach',
+                    'endif',
+                    'endswitch',
+                    'endwhile',
+                    'eval',
+                    'exit',
+                    'extends',
+                    'false',
+                    'final',
+                    'float',
+                    'for',
+                    'foreach',
+                    'function',
+                    'global',
+                    'goto',
+                    'if',
+                    'implements',
+                    'include',
+                    'include_once',
+                    'instanceof',
+                    'insteadof',
+                    'int',
+                    'interface',
+                    'isset',
+                    'list',
+                    'mixed',
+                    'namespace',
+                    'new',
+                    'null',
+                    'numeric',
+                    'object',
+                    'or',
+                    'print',
+                    'private',
+                    'protected',
+                    'public',
+                    'require',
+                    'require_once',
+                    'resource',
+                    'return',
+                    'static',
+                    'string',
+                    'switch',
+                    'throw',
+                    'trait',
+                    'true',
+                    'try',
+                    'unset',
+                    'use',
+                    'var',
+                    'void',
+                    'while',
+                    'xor',
+                    'yield',
+                    '__CLASS__',
+                    '__DIR__',
+                    '__FILE__',
+                    '__FUNCTION__',
+                    '__LINE__',
+                    '__METHOD__',
+                    '__NAMESPACE__',
+                    '__TRAIT__'
+                ]
+            )
+            ->when(function () use ($keywords) {
+                foreach ($keywords as $keyword) {
+                    $this
+                        ->boolean(SUT::isKeyword($keyword))
+                            ->isTrue();
+                }
+            });
+    }
+
+    public function case_is_identifier()
+    {
+        $this
+            ->given($_identifier = $this->realdom->regex('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#'))
+            ->when(function () use ($_identifier) {
+                foreach ($this->sampleMany($_identifier, 1000) as $identifier) {
+                    $this
+                        ->boolean(SUT::isIdentifier($identifier))
+                            ->isTrue();
+                }
+            });
+    }
+
+    public function case_register_shutdown_function()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $callable = function () {
+                },
+                $this->function->register_shutdown_function = function ($_callable) use (&$called, $self, &$callable) {
+                    $called = true;
+
+                    $self
+                        ->variable($_callable)
+                            ->isEqualTo($callable);
+
+                    return true;
+                }
+            )
+            ->when($result = SUT::registerShutdownFunction($callable))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_get_php_binary_with_constant()
+    {
+        $this
+            ->given($this->constant->PHP_BINARY = '/foo/php')
+            ->when($result = SUT::getPHPBinary())
+            ->then
+                ->string($result)
+                    ->isEqualTo('/foo/php');
+    }
+
+    public function case_get_php_binary_with_server()
+    {
+        $this
+            ->given(
+                $this->function->defined = false,
+                $_SERVER['_'] = '/bar/php'
+            )
+            ->when($result = SUT::getPHPBinary())
+            ->then
+                ->string($result)
+                    ->isEqualTo('/bar/php');
+    }
+
+    public function case_get_php_binary_with_bin_directory()
+    {
+        unset($_SERVER['_']);
+
+        $this
+            ->given(
+                $this->function->defined = false,
+                $this->function->file_exists = true,
+                $this->function->realpath = '/baz/php'
+            )
+            ->when($result = SUT::getPHPBinary())
+            ->then
+                ->string($result)
+                    ->isEqualTo('/baz/php');
+    }
+
+    public function case_uuid()
+    {
+        $this
+            ->given($this->function->mt_rand = 42)
+            ->when($result = SUT::uuid())
+            ->then
+                ->string($result)
+                    ->isEqualTo('002a002a-002a-402a-802a-002a002a002a');
+    }
+
+    public function case_uuid_all_differents()
+    {
+        $this
+            ->when(function () {
+                $uuids = [];
+
+                for ($i = 0; $i < 10000; ++$i) {
+                    $uuids[] = SUT::uuid();
+                }
+
+                $this
+                    ->integer(count($uuids))
+                        ->isEqualTo(count(array_unique($uuids)));
+            });
+    }
+}
diff --git a/vendor/hoa/consistency/Test/Unit/Exception.php b/vendor/hoa/consistency/Test/Unit/Exception.php
new file mode 100644 (file)
index 0000000..7ea3f96
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency\Test\Unit;
+
+use Hoa\Consistency\Exception as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Consistency\Test\Unit\Exception.
+ *
+ * Test suite of the exception.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends Test\Unit\Suite
+{
+    public function case_hoa_exception()
+    {
+        $this
+            ->when($result = new SUT('foo', 0))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Exception\Exception');
+    }
+}
diff --git a/vendor/hoa/consistency/Test/Unit/Xcallable.php b/vendor/hoa/consistency/Test/Unit/Xcallable.php
new file mode 100644 (file)
index 0000000..61e9ed5
--- /dev/null
@@ -0,0 +1,341 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency\Test\Unit;
+
+use Hoa\Consistency\Xcallable as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Consistency\Test\Unit\Xcallable.
+ *
+ * Test suite of the xcallable class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Xcallable extends Test\Unit\Suite
+{
+    public function case_form_function()
+    {
+        $this
+            ->when($result = new SUT('strtoupper'))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->string($result->getValidCallback())
+                    ->isEqualTo('strtoupper')
+                ->string($result->getHash())
+                    ->isEqualTo('function#strtoupper')
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionFunction')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtoupper');
+    }
+
+    public function case_form_class___method()
+    {
+        $this
+            ->when($result = new SUT(__CLASS__ . '::strtoupper'))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([__CLASS__, 'strtoupper'])
+                ->string($result->getHash())
+                    ->isEqualTo('class#' . __CLASS__ . '::strtoupper')
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtoupper');
+    }
+
+    public function case_form_class_method()
+    {
+        $this
+            ->when($result = new SUT(__CLASS__, 'strtoupper'))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([__CLASS__, 'strtoupper'])
+                ->string($result->getHash())
+                    ->isEqualTo('class#' . __CLASS__ . '::strtoupper')
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtoupper');
+    }
+
+    public function case_form_object_method()
+    {
+        $this
+            ->when($result = new SUT($this, 'strtolower'))
+            ->then
+                ->string($result('FOO'))
+                    ->isEqualTo('foo')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([$this, 'strtolower'])
+                ->string($result->getHash())
+                    ->matches(
+                        '/^object\([^:]+\)#' .
+                        preg_quote(__CLASS__) .
+                        '::strtolower$/'
+                    )
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtolower');
+    }
+
+    public function case_form_object_invoke()
+    {
+        $this
+            ->when($result = new SUT($this))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([$this, '__invoke'])
+                ->string($result->getHash())
+                    ->matches(
+                        '/^object\([^:]+\)#' .
+                        preg_quote(__CLASS__) .
+                        '::__invoke$/'
+                    )
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('__invoke');
+    }
+
+    public function case_form_closure()
+    {
+        $this
+            ->given(
+                $closure = function ($string) {
+                    return strtoupper($string);
+                }
+            )
+            ->when($result = new SUT($closure))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->object($result->getValidCallback())
+                    ->isIdenticalTo($closure)
+                ->string($result->getHash())
+                    ->matches('/^closure\([^:]+\)$/')
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionFunction')
+                ->string($reflection->getName())
+                    ->isEqualTo('Hoa\Consistency\Test\Unit\{closure}');
+    }
+
+    public function case_form_array_of_class_method()
+    {
+        $this
+            ->when($result = new SUT([__CLASS__, 'strtoupper']))
+            ->then
+                ->string($result('foo'))
+                    ->isEqualTo('FOO')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([__CLASS__, 'strtoupper'])
+                ->string($result->getHash())
+                    ->isEqualTo('class#' . __CLASS__ . '::strtoupper')
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtoupper');
+    }
+
+    public function case_form_array_of_object_method()
+    {
+        $this
+            ->when($result = new SUT([$this, 'strtolower']))
+            ->then
+                ->string($result('FOO'))
+                    ->isEqualTo('foo')
+                ->array($result->getValidCallback())
+                    ->isEqualTo([$this, 'strtolower'])
+                ->string($result->getHash())
+                    ->matches(
+                        '/^object\([^:]+\)#' .
+                        preg_quote(__CLASS__) .
+                        '::strtolower$/'
+                    )
+                    ->isEqualTo($result . '')
+                ->object($reflection = $result->getReflection())
+                    ->isInstanceOf('ReflectionMethod')
+                ->string($reflection->getName())
+                    ->isEqualTo('strtolower');
+    }
+
+    public function case_form_able_not_a_string()
+    {
+        $this
+            ->exception(function () {
+                new SUT(__CLASS__, 123);
+            })
+                ->isInstanceOf('Hoa\Consistency\Exception');
+    }
+
+    public function case_form_function_not_defined()
+    {
+        $this
+            ->exception(function () {
+                new SUT('__hoa_test_undefined_function__');
+            })
+                ->isInstanceOf('Hoa\Consistency\Exception');
+    }
+
+    public function case_form_able_cannot_be_deduced()
+    {
+        $this
+            ->given($this->function->method_exists = false)
+            ->exception(function () {
+                new SUT($this);
+            })
+                ->isInstanceOf('Hoa\Consistency\Exception');
+    }
+
+    public function case_invoke()
+    {
+        $this
+            ->given(
+                $callable = new SUT(
+                    function ($x, $y, $z) {
+                        return [$x, $y, $z];
+                    }
+                )
+            )
+            ->when($result = $callable(7, [4.2], 'foo'))
+            ->then
+                ->array($result)
+                    ->isEqualTo([7, [4.2], 'foo']);
+    }
+
+    public function case_distribute_arguments()
+    {
+        $this
+            ->given(
+                $callable = new SUT(
+                    function ($x, $y, $z) {
+                        return [$x, $y, $z];
+                    }
+                )
+            )
+            ->when($result = $callable->distributeArguments([7, [4.2], 'foo']))
+            ->then
+                ->array($result)
+                    ->isEqualTo([7, [4.2], 'foo']);
+    }
+
+    protected function _get_valid_callback_stream_xxx($argument, $method)
+    {
+        $this
+            ->given(
+                $stream    = new \Mock\Hoa\Stream\IStream\Out(),
+                $arguments = [$argument],
+                $xcallable = new SUT($stream)
+            )
+            ->when($result = $xcallable->getValidCallback($arguments))
+            ->then
+                ->array($result)
+                    ->isEqualTo([$stream, $method]);
+    }
+
+    public function case_get_valid_callback_stream_character()
+    {
+        return $this->_get_valid_callback_stream_xxx('f', 'writeCharacter');
+    }
+
+    public function case_get_valid_callback_stream_string()
+    {
+        return $this->_get_valid_callback_stream_xxx('foo', 'writeString');
+    }
+
+    public function case_get_valid_callback_stream_boolean()
+    {
+        return $this->_get_valid_callback_stream_xxx(true, 'writeBoolean');
+    }
+
+    public function case_get_valid_callback_stream_integer()
+    {
+        return $this->_get_valid_callback_stream_xxx(7, 'writeInteger');
+    }
+
+    public function case_get_valid_callback_stream_array()
+    {
+        return $this->_get_valid_callback_stream_xxx([4, 2], 'writeArray');
+    }
+
+    public function case_get_valid_callback_stream_float()
+    {
+        return $this->_get_valid_callback_stream_xxx(4.2, 'writeFloat');
+    }
+
+    public function case_get_valid_callback_stream_other()
+    {
+        return $this->_get_valid_callback_stream_xxx($this, 'writeAll');
+    }
+
+    public static function strtoupper($string)
+    {
+        return strtoupper($string);
+    }
+
+    public function strtolower($string)
+    {
+        return strtolower($string);
+    }
+
+    public function __invoke($string)
+    {
+        return strtoupper($string);
+    }
+
+    public function __toString()
+    {
+        return 'hello';
+    }
+}
diff --git a/vendor/hoa/consistency/Xcallable.php b/vendor/hoa/consistency/Xcallable.php
new file mode 100644 (file)
index 0000000..997b0b6
--- /dev/null
@@ -0,0 +1,316 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Consistency;
+
+use Hoa\Event;
+use Hoa\Stream;
+
+/**
+ * Class Hoa\Consistency\Xcallable.
+ *
+ * Build a callable object, i.e. function, class::method, object->method or
+ * closure, they all have the same behaviour. This callable is an extension of
+ * native PHP callable (aka callback) to integrate Hoa's structures.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Xcallable
+{
+    /**
+     * Callback, with the PHP format.
+     *
+     * @var mixed
+     */
+    protected $_callback = null;
+
+    /**
+     * Callable hash.
+     *
+     * @var string
+     */
+    protected $_hash     = null;
+
+
+
+    /**
+     * Build a callback.
+     * Accepted forms:
+     *     * `'function'`,
+     *     * `'class::method'`,
+     *     * `'class', 'method'`,
+     *     * `$object, 'method'`,
+     *     * `$object, ''`,
+     *     * `function (…) { … }`,
+     *     * `['class', 'method']`,
+     *     * `[$object, 'method']`.
+     *
+     * @param   mixed   $call    First callable part.
+     * @param   mixed   $able    Second callable part (if needed).
+     */
+    public function __construct($call, $able = '')
+    {
+        if ($call instanceof \Closure) {
+            $this->_callback = $call;
+
+            return;
+        }
+
+        if (!is_string($able)) {
+            throw new Exception(
+                'Bad callback form; the able part must be a string.',
+                0
+            );
+        }
+
+        if ('' === $able) {
+            if (is_string($call)) {
+                if (false === strpos($call, '::')) {
+                    if (!function_exists($call)) {
+                        throw new Exception(
+                            'Bad callback form; function %s does not exist.',
+                            1,
+                            $call
+                        );
+                    }
+
+                    $this->_callback = $call;
+
+                    return;
+                }
+
+                list($call, $able) = explode('::', $call);
+            } elseif (is_object($call)) {
+                if ($call instanceof Stream\IStream\Out) {
+                    $able = null;
+                } elseif (method_exists($call, '__invoke')) {
+                    $able = '__invoke';
+                } else {
+                    throw new Exception(
+                        'Bad callback form; an object but without a known ' .
+                        'method.',
+                        2
+                    );
+                }
+            } elseif (is_array($call) && isset($call[0])) {
+                if (!isset($call[1])) {
+                    return $this->__construct($call[0]);
+                }
+
+                return $this->__construct($call[0], $call[1]);
+            } else {
+                throw new Exception(
+                    'Bad callback form.',
+                    3
+                );
+            }
+        }
+
+        $this->_callback = [$call, $able];
+
+        return;
+    }
+
+    /**
+     * Call the callable.
+     *
+     * @param   ...
+     * @return  mixed
+     */
+    public function __invoke()
+    {
+        $arguments = func_get_args();
+        $valid     = $this->getValidCallback($arguments);
+
+        return call_user_func_array($valid, $arguments);
+    }
+
+    /**
+     * Distribute arguments according to an array.
+     *
+     * @param   array  $arguments    Arguments.
+     * @return  mixed
+     */
+    public function distributeArguments(array $arguments)
+    {
+        return call_user_func_array([$this, '__invoke'], $arguments);
+    }
+
+    /**
+     * Get a valid callback in the PHP meaning.
+     *
+     * @param   array   &$arguments    Arguments (could determine method on an
+     *                                 object if not precised).
+     * @return  mixed
+     */
+    public function getValidCallback(array &$arguments = [])
+    {
+        $callback = $this->_callback;
+        $head     = null;
+
+        if (isset($arguments[0])) {
+            $head = &$arguments[0];
+        }
+
+        // If method is undetermined, we find it (we understand event bucket and
+        // stream).
+        if (null !== $head &&
+            is_array($callback) &&
+            null === $callback[1]) {
+            if ($head instanceof Event\Bucket) {
+                $head = $head->getData();
+            }
+
+            switch ($type = gettype($head)) {
+                case 'string':
+                    if (1 === strlen($head)) {
+                        $method = 'writeCharacter';
+                    } else {
+                        $method = 'writeString';
+                    }
+
+                    break;
+
+                case 'boolean':
+                case 'integer':
+                case 'array':
+                    $method = 'write' . ucfirst($type);
+
+                    break;
+
+                case 'double':
+                    $method = 'writeFloat';
+
+                    break;
+
+                default:
+                    $method = 'writeAll';
+                    $head   = $head . "\n";
+            }
+
+            $callback[1] = $method;
+        }
+
+        return $callback;
+    }
+
+    /**
+     * Get hash.
+     * Will produce:
+     *     * function#…;
+     *     * class#…::…;
+     *     * object(…)#…::…;
+     *     * closure(…).
+     *
+     * @return  string
+     */
+    public function getHash()
+    {
+        if (null !== $this->_hash) {
+            return $this->_hash;
+        }
+
+        $_ = &$this->_callback;
+
+        if (is_string($_)) {
+            return $this->_hash = 'function#' . $_;
+        }
+
+        if (is_array($_)) {
+            return
+                $this->_hash =
+                    (is_object($_[0])
+                        ? 'object(' . spl_object_hash($_[0]) . ')' .
+                          '#' . get_class($_[0])
+                        : 'class#' . $_[0]) .
+                    '::' .
+                    (null !== $_[1]
+                        ? $_[1]
+                        : '???');
+        }
+
+        return $this->_hash = 'closure(' . spl_object_hash($_) . ')';
+    }
+
+    /**
+     * Get appropriated reflection instance.
+     *
+     * @param   ...
+     * @return  \Reflector
+     */
+    public function getReflection()
+    {
+        $arguments = func_get_args();
+        $valid     = $this->getValidCallback($arguments);
+
+        if (is_string($valid)) {
+            return new \ReflectionFunction($valid);
+        }
+
+        if ($valid instanceof \Closure) {
+            return new \ReflectionFunction($valid);
+        }
+
+        if (is_array($valid)) {
+            if (is_string($valid[0])) {
+                if (false === method_exists($valid[0], $valid[1])) {
+                    return new \ReflectionClass($valid[0]);
+                }
+
+                return new \ReflectionMethod($valid[0], $valid[1]);
+            }
+
+            $object = new \ReflectionObject($valid[0]);
+
+            if (null === $valid[1]) {
+                return $object;
+            }
+
+            return $object->getMethod($valid[1]);
+        }
+    }
+
+    /**
+     * Return the hash.
+     *
+     * @return  string
+     */
+    public function __toString()
+    {
+        return $this->getHash();
+    }
+}
diff --git a/vendor/hoa/consistency/composer.json b/vendor/hoa/consistency/composer.json
new file mode 100644 (file)
index 0000000..9ce7778
--- /dev/null
@@ -0,0 +1,45 @@
+{
+    "name"       : "hoa/consistency",
+    "description": "The Hoa\\Consistency library.",
+    "type"       : "library",
+    "keywords"   : ["library", "consistency", "autoloader", "entity", "flex",
+                    "keyword", "callable"],
+    "homepage"   : "https://hoa-project.net/",
+    "license"    : "BSD-3-Clause",
+    "authors"    : [
+        {
+            "name" : "Ivan Enderlin",
+            "email": "ivan.enderlin@hoa-project.net"
+        },
+        {
+            "name"    : "Hoa community",
+            "homepage": "https://hoa-project.net/"
+        }
+    ],
+    "support": {
+        "email" : "support@hoa-project.net",
+        "irc"   : "irc://chat.freenode.net/hoaproject",
+        "forum" : "https://users.hoa-project.net/",
+        "docs"  : "https://central.hoa-project.net/Documentation/Library/Consistency",
+        "source": "https://central.hoa-project.net/Resource/Library/Consistency"
+    },
+    "require": {
+        "php"          : ">=5.5.0",
+        "hoa/exception": "~1.0"
+    },
+    "require-dev": {
+        "hoa/stream": "~1.0",
+        "hoa/test"  : "~2.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Hoa\\Consistency\\": "."
+        },
+        "files": ["Prelude.php"]
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.x-dev"
+        }
+    }
+}
diff --git a/vendor/hoa/event/.State b/vendor/hoa/event/.State
new file mode 100644 (file)
index 0000000..a604de4
--- /dev/null
@@ -0,0 +1 @@
+finalized
diff --git a/vendor/hoa/event/.gitignore b/vendor/hoa/event/.gitignore
new file mode 100644 (file)
index 0000000..4fbb073
--- /dev/null
@@ -0,0 +1,2 @@
+/vendor/
+/composer.lock
diff --git a/vendor/hoa/event/Bucket.php b/vendor/hoa/event/Bucket.php
new file mode 100644 (file)
index 0000000..968350d
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+/**
+ * Class \Hoa\Event\Bucket.
+ *
+ * This class is the object which is transmit through event channels.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Bucket
+{
+    /**
+     * Source object.
+     *
+     * @var \Hoa\Event\Source
+     */
+    protected $_source = null;
+
+    /**
+     * Data.
+     *
+     * @var mixed
+     */
+    protected $_data   = null;
+
+
+
+    /**
+     * Set data.
+     *
+     * @param   mixed   $data    Data.
+     */
+    public function __construct($data = null)
+    {
+        $this->setData($data);
+
+        return;
+    }
+
+    /**
+     * Send this object on the event channel.
+     *
+     * @param   string             $eventId    Event ID.
+     * @param   \Hoa\Event\Source  $source     Source.
+     * @return  void
+     */
+    public function send($eventId, Source $source)
+    {
+        return Event::notify($eventId, $source, $this);
+    }
+
+    /**
+     * Set source.
+     *
+     * @param   \Hoa\Event\Source  $source    Source.
+     * @return  \Hoa\Event\Source
+     */
+    public function setSource(Source $source)
+    {
+        $old           = $this->_source;
+        $this->_source = $source;
+
+        return $old;
+    }
+
+    /**
+     * Get source.
+     *
+     * @return  \Hoa\Event\Source
+     */
+    public function getSource()
+    {
+        return $this->_source;
+    }
+
+    /**
+     * Set data.
+     *
+     * @param   mixed   $data    Data.
+     * @return  mixed
+     */
+    public function setData($data)
+    {
+        $old         = $this->_data;
+        $this->_data = $data;
+
+        return $old;
+    }
+
+    /**
+     * Get data.
+     *
+     * @return  mixed
+     */
+    public function getData()
+    {
+        return $this->_data;
+    }
+}
diff --git a/vendor/hoa/event/CHANGELOG.md b/vendor/hoa/event/CHANGELOG.md
new file mode 100644 (file)
index 0000000..7e646a0
--- /dev/null
@@ -0,0 +1,44 @@
+# 1.17.01.13
+
+  * Quality: Happy new year! (Alexis von Glasow, 2017-01-11T23:09:35+01:00)
+
+# 1.16.11.19
+
+  * Documentation: New `README.md` file. (Ivan Enderlin, 2016-10-18T16:34:43+02:00)
+  * Documentation: Update `support` properties. (Ivan Enderlin, 2016-10-05T20:36:30+02:00)
+
+# 1.16.03.15
+
+  * Fix a typo (Metalaka, 2016-01-28T09:05:40+01:00)
+  * CHANGELOG: Add a missing newline. (Ivan Enderlin, 2016-01-11T09:37:32+01:00)
+
+# 1.16.01.11
+
+  * Quality: Drop PHP5.4. (Ivan Enderlin, 2016-01-11T09:15:26+01:00)
+  * Quality: Run devtools:cs. (Ivan Enderlin, 2016-01-09T09:01:10+01:00)
+  * Core: Remove `Hoa\Core`. (Ivan Enderlin, 2016-01-09T08:14:54+01:00)
+  * Consistency: Use `Hoa\Consistency`. (Ivan Enderlin, 2015-12-08T11:10:00+01:00)
+  * Documentation: Fix typos. (Ivan Enderlin, 2015-11-23T22:05:56+01:00)
+  * Exception: Use `Hoa\Exception`. (Ivan Enderlin, 2015-11-20T07:40:34+01:00)
+
+# 0.15.11.23
+
+  * Documentation: Fix typos. (Ivan Enderlin, 2015-11-23T22:05:56+01:00)
+  * Exception: Use `Hoa\Exception`. (Ivan Enderlin, 2015-11-20T07:40:34+01:00)
+  * Test: Fix a conflict between 2 test suites. (Ivan Enderlin, 2015-11-23T21:29:28+01:00)
+  * Test: Write test suite for `Hoa\Event\Listens`. (Ivan Enderlin, 2015-11-23T21:25:49+01:00)
+  * Listener: Add the `Listens` trait. (Ivan Enderlin, 2015-11-20T06:45:11+01:00)
+  * Documentation: Fix a typo. (Ivan Enderlin, 2015-11-23T13:01:56+01:00)
+  * Improve readability by adding constants to registered events container. (Metalaka, 2015-11-20T19:53:32+01:00)
+  * Add a `.gitignore` file. (Metalaka, 2015-11-20T19:37:52+01:00)
+  * README: Complete description and add usage. (Ivan Enderlin, 2015-11-13T08:43:08+01:00)
+  * Test: Write test suite for `Hoa\Event\Event`. (Ivan Enderlin, 2015-11-11T17:04:41+01:00)
+  * Test: Write test suite for `Hoa\Event\Exception`. (Ivan Enderlin, 2015-11-11T16:46:12+01:00)
+  * Composer: Add a keyword. (Ivan Enderlin, 2015-11-11T13:38:35+01:00)
+  * Test: Write test suite for `Hoa\Event\Listener`. (Ivan Enderlin, 2015-11-11T13:27:40+01:00)
+  * Test: Write test suite for `Hoa\Event\Source`. (Ivan Enderlin, 2015-11-10T21:56:37+01:00)
+  * Test: Write test suite for `Hoa\Event\Listenable`. (Ivan Enderlin, 2015-11-10T21:56:24+01:00)
+  * Test: Write test suite for `Hoa\Event\Bucket`. (Ivan Enderlin, 2015-11-10T21:55:45+01:00)
+  * Split from `Hoa\Core`. (Ivan Enderlin, 2015-11-10T21:28:31+01:00)
+
+(first snapshot)
diff --git a/vendor/hoa/event/Event.php b/vendor/hoa/event/Event.php
new file mode 100644 (file)
index 0000000..23b3292
--- /dev/null
@@ -0,0 +1,266 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+use Hoa\Consistency;
+
+/**
+ * Class \Hoa\Event\Event.
+ *
+ * Events are asynchronous at registration, anonymous at use (until we
+ * receive a bucket) and useful to largely spread data through components
+ * without any known connection between them.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Event
+{
+    /**
+     * Event ID key.
+     *
+     * @const int
+     */
+    const KEY_EVENT  = 0;
+
+    /**
+     * Source object key.
+     *
+     * @const int
+     */
+    const KEY_SOURCE = 1;
+
+    /**
+     * Static register of all observable objects, i.e. \Hoa\Event\Source
+     * object, i.e. object that can send event.
+     *
+     * @var array
+     */
+    private static $_register = [];
+
+    /**
+     * Callables, i.e. observer objects.
+     *
+     * @var array
+     */
+    protected $_callable      = [];
+
+
+
+    /**
+     * Privatize the constructor.
+     *
+     */
+    private function __construct()
+    {
+        return;
+    }
+
+    /**
+     * Manage multiton of events, with the principle of asynchronous
+     * attachments.
+     *
+     * @param   string  $eventId    Event ID.
+     * @return  \Hoa\Event\Event
+     */
+    public static function getEvent($eventId)
+    {
+        if (!isset(self::$_register[$eventId][self::KEY_EVENT])) {
+            self::$_register[$eventId] = [
+                self::KEY_EVENT  => new self(),
+                self::KEY_SOURCE => null
+            ];
+        }
+
+        return self::$_register[$eventId][self::KEY_EVENT];
+    }
+
+    /**
+     * Declare a new object in the observable collection.
+     * Note: Hoa's libraries use hoa://Event/AnID for their observable objects;
+     *
+     * @param   string                    $eventId    Event ID.
+     * @param   \Hoa\Event\Source|string  $source     Observable object or class.
+     * @return  void
+     * @throws  \Hoa\Event\Exception
+     */
+    public static function register($eventId, $source)
+    {
+        if (true === self::eventExists($eventId)) {
+            throw new Exception(
+                'Cannot redeclare an event with the same ID, i.e. the event ' .
+                'ID %s already exists.',
+                0,
+                $eventId
+            );
+        }
+
+        if (is_object($source) && !($source instanceof Source)) {
+            throw new Exception(
+                'The source must implement \Hoa\Event\Source ' .
+                'interface; given %s.',
+                1,
+                get_class($source)
+            );
+        } else {
+            $reflection = new \ReflectionClass($source);
+
+            if (false === $reflection->implementsInterface('\Hoa\Event\Source')) {
+                throw new Exception(
+                    'The source must implement \Hoa\Event\Source ' .
+                    'interface; given %s.',
+                    2,
+                    $source
+                );
+            }
+        }
+
+        if (!isset(self::$_register[$eventId][self::KEY_EVENT])) {
+            self::$_register[$eventId][self::KEY_EVENT] = new self();
+        }
+
+        self::$_register[$eventId][self::KEY_SOURCE] = $source;
+
+        return;
+    }
+
+    /**
+     * Undeclare an object in the observable collection.
+     *
+     * @param   string  $eventId    Event ID.
+     * @param   bool    $hard       If false, just delete the source, else,
+     *                              delete source and attached callables.
+     * @return  void
+     */
+    public static function unregister($eventId, $hard = false)
+    {
+        if (false !== $hard) {
+            unset(self::$_register[$eventId]);
+        } else {
+            self::$_register[$eventId][self::KEY_SOURCE] = null;
+        }
+
+        return;
+    }
+
+    /**
+     * Attach an object to an event.
+     * It can be a callable or an accepted callable form (please, see the
+     * \Hoa\Consistency\Xcallable class).
+     *
+     * @param   mixed   $callable    Callable.
+     * @return  \Hoa\Event\Event
+     */
+    public function attach($callable)
+    {
+        $callable                              = xcallable($callable);
+        $this->_callable[$callable->getHash()] = $callable;
+
+        return $this;
+    }
+
+    /**
+     * Detach an object to an event.
+     * Please see $this->attach() method.
+     *
+     * @param   mixed   $callable    Callable.
+     * @return  \Hoa\Event\Event
+     */
+    public function detach($callable)
+    {
+        unset($this->_callable[xcallable($callable)->getHash()]);
+
+        return $this;
+    }
+
+    /**
+     * Check if at least one callable is attached to an event.
+     *
+     * @return  bool
+     */
+    public function isListened()
+    {
+        return !empty($this->_callable);
+    }
+
+    /**
+     * Notify, i.e. send data to observers.
+     *
+     * @param   string             $eventId    Event ID.
+     * @param   \Hoa\Event\Source  $source     Source.
+     * @param   \Hoa\Event\Bucket  $data       Data.
+     * @return  void
+     * @throws  \Hoa\Event\Exception
+     */
+    public static function notify($eventId, Source $source, Bucket $data)
+    {
+        if (false === self::eventExists($eventId)) {
+            throw new Exception(
+                'Event ID %s does not exist, cannot send notification.',
+                3,
+                $eventId
+            );
+        }
+
+        $data->setSource($source);
+        $event = self::getEvent($eventId);
+
+        foreach ($event->_callable as $callable) {
+            $callable($data);
+        }
+
+        return;
+    }
+
+    /**
+     * Check whether an event exists.
+     *
+     * @param   string  $eventId    Event ID.
+     * @return  bool
+     */
+    public static function eventExists($eventId)
+    {
+        return
+            array_key_exists($eventId, self::$_register) &&
+            self::$_register[$eventId][self::KEY_SOURCE] !== null;
+    }
+}
+
+/**
+ * Flex entity.
+ */
+Consistency::flexEntity('Hoa\Event\Event');
diff --git a/vendor/hoa/event/Exception.php b/vendor/hoa/event/Exception.php
new file mode 100644 (file)
index 0000000..94b92f7
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+use Hoa\Exception as HoaException;
+
+/**
+ * Class \Hoa\Event\Exception.
+ *
+ * Extending the \Hoa\Exception\Exception class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends HoaException
+{
+}
diff --git a/vendor/hoa/event/Listenable.php b/vendor/hoa/event/Listenable.php
new file mode 100644 (file)
index 0000000..3fa5a70
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+/**
+ * Interface \Hoa\Event\Listenable.
+ *
+ * Each object which is listenable must implement this interface.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+interface Listenable extends Source
+{
+    /**
+     * Attach a callable to a listenable component.
+     *
+     * @param   string  $listenerId    Listener ID.
+     * @param   mixed   $callable      Callable.
+     * @return  \Hoa\Event\Listenable
+     */
+    public function on($listenerId, $callable);
+}
diff --git a/vendor/hoa/event/Listener.php b/vendor/hoa/event/Listener.php
new file mode 100644 (file)
index 0000000..2cc8adc
--- /dev/null
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+/**
+ * Class \Hoa\Event\Listener.
+ *
+ * A contrario of events, listeners are synchronous, identified at use and
+ * useful for close interactions between one or some components.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Listener
+{
+    /**
+     * Source of listener (for Bucket).
+     *
+     * @var \Hoa\Event\Listenable
+     */
+    protected $_source    = null;
+
+    /**
+     * All listener IDs and associated listeners.
+     *
+     * @var array
+     */
+    protected $_callables = [];
+
+
+
+    /**
+     * Build a listener.
+     *
+     * @param   \Hoa\Event\Listenable  $source    Source (for Bucket).
+     * @param   array                  $ids       Accepted ID.
+     */
+    public function __construct(Listenable $source, array $ids)
+    {
+        $this->_source = $source;
+        $this->addIds($ids);
+
+        return;
+    }
+
+    /**
+     * Add acceptable ID (or reset).
+     *
+     * @param   array  $ids    Accepted ID.
+     * @return  void
+     */
+    public function addIds(array $ids)
+    {
+        foreach ($ids as $id) {
+            $this->_callables[$id] = [];
+        }
+
+        return;
+    }
+
+    /**
+     * Attach a callable to a listenable component.
+     *
+     * @param   string  $listenerId    Listener ID.
+     * @param   mixed   $callable      Callable.
+     * @return  \Hoa\Event\Listener
+     * @throws  \Hoa\Event\Exception
+     */
+    public function attach($listenerId, $callable)
+    {
+        if (false === $this->listenerExists($listenerId)) {
+            throw new Exception(
+                'Cannot listen %s because it is not defined.',
+                0,
+                $listenerId
+            );
+        }
+
+        $callable                                            = xcallable($callable);
+        $this->_callables[$listenerId][$callable->getHash()] = $callable;
+
+        return $this;
+    }
+
+    /**
+     * Detach a callable from a listenable component.
+     *
+     * @param   string  $listenerId    Listener ID.
+     * @param   mixed   $callable      Callable.
+     * @return  \Hoa\Event\Listener
+     */
+    public function detach($listenerId, $callable)
+    {
+        unset($this->_callables[$listenerId][xcallable($callable)->getHash()]);
+
+        return $this;
+    }
+
+    /**
+     * Detach all callables from a listenable component.
+     *
+     * @param  string  $listenerId    Listener ID.
+     * @return \Hoa\Event\Listener
+     */
+    public function detachAll($listenerId)
+    {
+        unset($this->_callables[$listenerId]);
+
+        return $this;
+    }
+
+    /**
+     * Check if a listener exists.
+     *
+     * @param   string  $listenerId    Listener ID.
+     * @return  bool
+     */
+    public function listenerExists($listenerId)
+    {
+        return array_key_exists($listenerId, $this->_callables);
+    }
+
+    /**
+     * Send/fire a bucket to a listener.
+     *
+     * @param   string             $listenerId    Listener ID.
+     * @param   \Hoa\Event\Bucket  $data          Data.
+     * @return  array
+     * @throws  \Hoa\Event\Exception
+     */
+    public function fire($listenerId, Bucket $data)
+    {
+        if (false === $this->listenerExists($listenerId)) {
+            throw new Exception(
+                'Cannot fire on %s because it is not defined.',
+                1,
+                $listenerId
+            );
+        }
+
+        $data->setSource($this->_source);
+        $out = [];
+
+        foreach ($this->_callables[$listenerId] as $callable) {
+            $out[] = $callable($data);
+        }
+
+        return $out;
+    }
+}
diff --git a/vendor/hoa/event/Listens.php b/vendor/hoa/event/Listens.php
new file mode 100644 (file)
index 0000000..83f6223
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+/**
+ * Trait \Hoa\Event\Listens.
+ *
+ * Implementation of a listener.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+trait Listens
+{
+    /**
+     * Listener instance.
+     *
+     * @var \Hoa\Event\Listener
+     */
+    protected $_listener = null;
+
+
+
+    /**
+     * Attach a callable to a listenable component.
+     *
+     * @param   string  $listenerId    Listener ID.
+     * @param   mixed   $callable      Callable.
+     * @return  \Hoa\Event\Listenable
+     */
+    public function on($listenerId, $callable)
+    {
+        $listener = $this->getListener();
+
+        if (null === $listener) {
+            throw new Exception(
+                'Cannot attach a callable to the listener %s because ' .
+                'it has not been initialized yet.',
+                0,
+                get_class($this)
+            );
+        }
+
+        $listener->attach($listenerId, $callable);
+
+        return $this;
+    }
+
+    /**
+     * Set listener.
+     *
+     * @param  \Hoa\Event\Listener  $listener    Listener.
+     * @return \Hoa\Event\Listener
+     */
+    protected function setListener(Listener $listener)
+    {
+        $old             = $this->_listener;
+        $this->_listener = $listener;
+
+        return $old;
+    }
+
+    /**
+     * Get listener.
+     *
+     * @return \Hoa\Event\Listener
+     */
+    protected function getListener()
+    {
+        return $this->_listener;
+    }
+}
diff --git a/vendor/hoa/event/README.md b/vendor/hoa/event/README.md
new file mode 100644 (file)
index 0000000..b5b8ed5
--- /dev/null
@@ -0,0 +1,161 @@
+<p align="center">
+  <img src="https://static.hoa-project.net/Image/Hoa.svg" alt="Hoa" width="250px" />
+</p>
+
+---
+
+<p align="center">
+  <a href="https://travis-ci.org/hoaproject/event"><img src="https://img.shields.io/travis/hoaproject/event/master.svg" alt="Build status" /></a>
+  <a href="https://coveralls.io/github/hoaproject/event?branch=master"><img src="https://img.shields.io/coveralls/hoaproject/event/master.svg" alt="Code coverage" /></a>
+  <a href="https://packagist.org/packages/hoa/event"><img src="https://img.shields.io/packagist/dt/hoa/event.svg" alt="Packagist" /></a>
+  <a href="https://hoa-project.net/LICENSE"><img src="https://img.shields.io/packagist/l/hoa/event.svg" alt="License" /></a>
+</p>
+<p align="center">
+  Hoa is a <strong>modular</strong>, <strong>extensible</strong> and
+  <strong>structured</strong> set of PHP libraries.<br />
+  Moreover, Hoa aims at being a bridge between industrial and research worlds.
+</p>
+
+# Hoa\Event
+
+[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
+[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
+[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Event)
+[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/event)
+
+This library allows to use events and listeners in PHP. This is an observer
+design-pattern implementation.
+
+[Learn more](https://central.hoa-project.net/Documentation/Library/Event).
+
+## Installation
+
+With [Composer](https://getcomposer.org/), to include this library into
+your dependencies, you need to
+require [`hoa/event`](https://packagist.org/packages/hoa/event):
+
+```sh
+$ composer require hoa/event '~1.0'
+```
+
+For more installation procedures, please read [the Source
+page](https://hoa-project.net/Source.html).
+
+## Testing
+
+Before running the test suites, the development dependencies must be installed:
+
+```sh
+$ composer install
+```
+
+Then, to run all the test suites:
+
+```sh
+$ vendor/bin/hoa test:run
+```
+
+For more information, please read the [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html).
+
+## Quick usage
+
+We propose a quick overview of how to use events and listeners.
+
+### Events
+
+An event is:
+  * **Asynchronous** when registering, because the observable may not exist yet
+    while observers start to observe,
+  * **Anonymous** when using, because the observable has no idea how many and
+    what observers are observing,
+  * It aims at a **large** diffusion of data through isolated components.
+    Wherever is the observable, we can observe its data.
+
+In Hoa, an event channel has the following form:
+`hoa://Event/LibraryName/AnId:pseudo-class#anAnchor`. For instance, the
+`hoa://Event/Exception` channel contains all exceptions that have been thrown.
+The `hoa://Event/Stream/StreamName:close-before` contains all streams that are
+about to close. Thus, the following example will observe all thrown exceptions:
+
+```php
+Hoa\Event\Event::getEvent('hoa://Event/Exception')->attach(
+    function (Hoa\Event\Bucket $bucket) {
+        var_dump(
+            $bucket->getSource(),
+            $bucket->getData()
+        );
+    }
+);
+```
+
+Because `attach` expects a callable and because Hoa's callable implementation is
+smart, we can directly attach a stream to an event, like:
+
+```php
+Hoa\Event\Event::getEvent('hoa://Event/Exception')->attach(
+    new Hoa\File\Write('Foo.log')
+);
+```
+
+This way, all exceptions will be printed on the `Foo.log` file.
+
+### Listeners
+
+Contrary to an event, a listener is:
+  * **Synchronous** when registering, because the observable must exist before
+    observers can observe,
+  * **Identified** when using, because the observable knows how many observers
+    are observing,
+  * It aims at a **close** diffusion of data. The observers must have an access
+    to the observable to observe.
+
+The `Hoa\Event\Listenable` interface requires the `on` method to be present to
+register a listener to a listener ID. For instance, the following example
+listens the `message` listener ID, i.e. when a message is received by the
+WebSocket server, the closure is executed:
+
+```php
+$server = new Hoa\Websocket\Server(…);
+$server->on('message', function (Hoa\Event\Bucket $bucket) {
+    var_dump(
+        $bucket->getSource(),
+        $bucket->getData()
+    );
+});
+```
+
+## Documentation
+
+The
+[hack book of `Hoa\Event`](https://central.hoa-project.net/Documentation/Library/Event) contains
+detailed information about how to use this library and how it works.
+
+To generate the documentation locally, execute the following commands:
+
+```sh
+$ composer require --dev hoa/devtools
+$ vendor/bin/hoa devtools:documentation --open
+```
+
+More documentation can be found on the project's website:
+[hoa-project.net](https://hoa-project.net/).
+
+## Getting help
+
+There are mainly two ways to get help:
+
+  * On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
+    IRC channel,
+  * On the forum at [users.hoa-project.net](https://users.hoa-project.net).
+
+## Contribution
+
+Do you want to contribute? Thanks! A detailed [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
+everything you need to know.
+
+## License
+
+Hoa is under the New BSD License (BSD-3-Clause). Please, see
+[`LICENSE`](https://hoa-project.net/LICENSE) for details.
diff --git a/vendor/hoa/event/Source.php b/vendor/hoa/event/Source.php
new file mode 100644 (file)
index 0000000..d1510ca
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event;
+
+/**
+ * Interface \Hoa\Event\Source.
+ *
+ * Each object which is listenable must implement this interface.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+interface Source
+{
+}
diff --git a/vendor/hoa/event/Test/Unit/Bucket.php b/vendor/hoa/event/Test/Unit/Bucket.php
new file mode 100644 (file)
index 0000000..0947bc2
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Event as LUT;
+use Hoa\Event\Bucket as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Bucket.
+ *
+ * Test suite of the bucket.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Bucket extends Test\Unit\Suite
+{
+    public function case_constructor()
+    {
+        $this
+            ->when($result = new SUT('foo'))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Event\Bucket')
+                ->string($result->getData())
+                    ->isEqualTo('foo');
+    }
+
+    public function case_send()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                LUT::register($eventId, $source),
+
+                $bucket = new SUT('foo'),
+
+                LUT::getEvent($eventId)->attach(
+                    function (SUT $receivedBucket) use ($self, $bucket, &$called) {
+                        $called = true;
+
+                        $self
+                            ->object($receivedBucket)
+                                ->isIdenticalTo($bucket);
+                    }
+                )
+            )
+            ->when($result = $bucket->send($eventId, $source))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_set_source()
+    {
+        $this
+            ->given(
+                $bucket  = new SUT(),
+                $sourceA = new \Mock\Hoa\Event\Source()
+            )
+            ->when($result = $bucket->setSource($sourceA))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->object($bucket->getSource())
+                    ->isIdenticalTo($sourceA)
+
+            ->given($sourceB = new \Mock\Hoa\Event\Source())
+            ->when($result = $bucket->setSource($sourceB))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($sourceA)
+                ->object($bucket->getSource())
+                    ->isIdenticalTo($sourceB);
+    }
+
+    public function case_set_data()
+    {
+        $this
+            ->given(
+                $bucket = new SUT(),
+                $datumA = 'foo'
+            )
+            ->when($result = $bucket->setData($datumA))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->string($bucket->getData())
+                    ->isEqualTo($datumA)
+
+            ->given($datumB = 'bar')
+            ->when($result = $bucket->setData($datumB))
+            ->then
+                ->string($result)
+                    ->isEqualTo($datumA)
+                ->string($bucket->getData())
+                    ->isEqualTo($datumB);
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Event.php b/vendor/hoa/event/Test/Unit/Event.php
new file mode 100644 (file)
index 0000000..daf03eb
--- /dev/null
@@ -0,0 +1,300 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Event as LUT;
+use Hoa\Event\Event as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Event.
+ *
+ * Test suite of the event class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Event extends Test\Unit\Suite
+{
+    public function case_multiton()
+    {
+        $this
+            ->given($eventId = 'hoa://Event/Test')
+            ->when($result = SUT::getEvent($eventId))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Event\Event')
+                ->object(SUT::getEvent($eventId))
+                    ->isIdenticalTo($result);
+    }
+
+    public function case_register_source_instance()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source()
+            )
+            ->when($result = SUT::register($eventId, $source))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean(SUT::eventExists($eventId))
+                    ->isTrue();
+    }
+
+    public function case_register_source_name()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = 'Mock\Hoa\Event\Source'
+            )
+            ->when($result = SUT::register($eventId, $source))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean(SUT::eventExists($eventId))
+                    ->isTrue();
+    }
+
+    public function case_register_redeclare()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                SUT::register($eventId, $source)
+            )
+            ->exception(function () use ($eventId, $source) {
+                SUT::register($eventId, $source);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+
+    public function case_register_not_a_source_instance()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \StdClass()
+            )
+            ->exception(function () use ($eventId, $source) {
+                $result = SUT::register($eventId, $source);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+
+    public function case_register_not_a_source_name()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = 'StdClass'
+            )
+            ->exception(function () use ($eventId, $source) {
+                $result = SUT::register($eventId, $source);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+
+    public function case_unregister()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                SUT::register($eventId, $source)
+            )
+            ->when($result = SUT::unregister($eventId))
+            ->then
+                ->boolean(SUT::eventExists($eventId))
+                    ->isFalse();
+    }
+
+    public function case_unregister_hard()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                SUT::register($eventId, $source),
+                $event = SUT::getEvent($eventId)
+            )
+            ->when($result = SUT::unregister($eventId, true))
+            ->then
+                ->boolean(SUT::eventExists($eventId))
+                    ->isFalse()
+                ->object(SUT::getEvent($eventId))
+                    ->isNotIdenticalTo($event);
+    }
+
+    public function case_unregister_not_registered()
+    {
+        $this
+            ->given($eventId = 'hoa://Event/Test')
+            ->when($result = SUT::unregister($eventId))
+            ->then
+                ->variable($result)
+                    ->isNull();
+    }
+
+    public function case_attach()
+    {
+        $this
+            ->given(
+                $event    = SUT::getEvent('hoa://Event/Test'),
+                $callable = function () { }
+            )
+            ->when($result = $event->attach($callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($event)
+                ->boolean($event->isListened())
+                    ->isTrue();
+    }
+
+    public function case_detach()
+    {
+        $this
+            ->given(
+                $event    = SUT::getEvent('hoa://Event/Test'),
+                $callable = function () { },
+                $event->attach($callable)
+            )
+            ->when($result = $event->detach($callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($event)
+                ->boolean($event->isListened())
+                    ->isFalse();
+    }
+
+    public function case_detach_unattached()
+    {
+        $this
+            ->given(
+                $event    = SUT::getEvent('hoa://Event/Test'),
+                $callable = function () { }
+            )
+            ->when($result = $event->detach($callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($event)
+                ->boolean($event->isListened())
+                    ->isFalse();
+    }
+
+    public function case_is_listened()
+    {
+        $this
+            ->given($event = SUT::getEvent('hoa://Event/Test'))
+            ->when($result = $event->isListened())
+            ->then
+                ->boolean($event->isListened())
+                    ->isFalse();
+    }
+
+    public function case_notify()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                $bucket  = new LUT\Bucket(),
+
+                SUT::register($eventId, $source),
+                SUT::getEvent($eventId)->attach(
+                    function (LUT\Bucket $receivedBucket) use ($self, $source, $bucket, &$called) {
+                        $called = true;
+
+                        $this
+                            ->object($receivedBucket)
+                                ->isIdenticalTo($bucket)
+                            ->object($receivedBucket->getSource())
+                                ->isIdenticalTo($source);
+                    }
+                )
+            )
+            ->when($result = SUT::notify($eventId, $source, $bucket))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_notify_unregistered_event_id()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                $data    = new LUT\Bucket()
+            )
+            ->exception(function () use ($eventId, $source, $data) {
+                SUT::notify($eventId, $source, $data);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+
+    public function case_event_exists()
+    {
+        $this
+            ->given(
+                $eventId = 'hoa://Event/Test',
+                $source  = new \Mock\Hoa\Event\Source(),
+                SUT::register($eventId, $source)
+            )
+            ->when($result = SUT::eventExists($eventId))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_event_not_exists()
+    {
+        $this
+            ->given($eventId = 'hoa://Event/Test')
+            ->when($result = SUT::eventExists($eventId))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Exception.php b/vendor/hoa/event/Test/Unit/Exception.php
new file mode 100644 (file)
index 0000000..e24f4af
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Event\Exception as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Exception.
+ *
+ * Test suite of the exception.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends Test\Unit\Suite
+{
+    public function case_hoa_exception()
+    {
+        $this
+            ->when($result = new SUT('foo', 0))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Exception\Exception');
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Listenable.php b/vendor/hoa/event/Test/Unit/Listenable.php
new file mode 100644 (file)
index 0000000..4ba1ca2
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Listenable.
+ *
+ * Test suite of the listenable interface.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Listenable extends Test\Unit\Suite
+{
+    public function case_interface()
+    {
+        $this
+            ->when($result = new \Mock\Hoa\Event\Listenable())
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Event\Listenable');
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Listener.php b/vendor/hoa/event/Test/Unit/Listener.php
new file mode 100644 (file)
index 0000000..8216302
--- /dev/null
@@ -0,0 +1,240 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Event as LUT;
+use Hoa\Event\Listener as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Listener.
+ *
+ * Test suite of the listener.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Listener extends Test\Unit\Suite
+{
+    public function case_constructor()
+    {
+        $this
+            ->given(
+                $source = new \Mock\Hoa\Event\Listenable(),
+                $ids    = ['foo', 'bar', 'baz']
+            )
+            ->when($result = new SUT($source, $ids))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Event\Listener')
+                ->boolean($result->listenerExists('foo'))
+                    ->isTrue()
+                ->boolean($result->listenerExists('bar'))
+                    ->isTrue()
+                ->boolean($result->listenerExists('baz'))
+                    ->isTrue();
+    }
+
+    public function case_attach()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'foo',
+                $listener   = new SUT($source, ['foo', 'bar']),
+                $callable   = function () {
+                    return 42;
+                }
+            )
+            ->when($result = $listener->attach($listenerId, $callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener)
+                ->array($listener->fire($listenerId, new LUT\Bucket()))
+                    ->isEqualTo([42]);
+    }
+
+    public function case_attach_to_an_undefined_listener()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'bar',
+                $listener   = new SUT($source, ['foo', 'baz']),
+                $callable   = function () { }
+            )
+            ->exception(function () use ($listener, $listenerId, $callable) {
+                $listener->attach($listenerId, $callable);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+
+    public function case_detach()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'foo',
+                $listener   = new SUT($source, ['foo', 'bar']),
+                $callable   = function () {
+                    return 42;
+                },
+                $listener->attach($listenerId, $callable)
+            )
+            ->when($result = $listener->detach($listenerId, $callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener)
+                ->array($listener->fire($listenerId, new LUT\Bucket()))
+                    ->isEmpty();
+    }
+
+    public function case_detach_an_undefined_listener()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'bar',
+                $listener   = new SUT($source, ['foo', 'baz']),
+                $callable   = function () { }
+            )
+            ->when($result = $listener->detach($listenerId, $callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener);
+    }
+
+    public function case_detach_all()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'foo',
+                $listener   = new SUT($source, ['foo', 'bar'])
+            )
+            ->when($result = $listener->detachAll($listenerId))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener)
+                ->boolean($listener->listenerExists($listenerId))
+                    ->isFalse();
+    }
+
+    public function case_detach_all_with_an_undefined_listener()
+    {
+        $this
+            ->given(
+                $source     = new \Mock\Hoa\Event\Listenable(),
+                $listenerId = 'bar',
+                $listener   = new SUT($source, ['foo', 'baz'])
+            )
+            ->when($result = $listener->detachAll($listenerId))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener);
+    }
+
+    public function case_listener_exists()
+    {
+        $this
+            ->given(
+                $source   = new \Mock\Hoa\Event\Listenable(),
+                $ids      = [],
+                $listener = new SUT($source, $ids)
+            )
+            ->when($listener->addIds(['foo']))
+            ->then
+                ->boolean($listener->listenerExists('foo'))
+                    ->isTrue()
+                ->boolean($listener->listenerExists('bar'))
+                    ->isFalse()
+
+            ->when($listener->addIds(['bar']))
+            ->then
+                ->boolean($listener->listenerExists('bar'))
+                    ->isTrue();
+    }
+
+    public function case_fire()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $source   = new \Mock\Hoa\Event\Listenable(),
+                $ids      = ['foo', 'bar'],
+                $listener = new SUT($source, $ids),
+
+                $listenerId = 'foo',
+                $bucket     = new LUT\Bucket(),
+                $listener->attach(
+                    $listenerId,
+                    function (LUT\Bucket $receivedBucket) use ($self, $bucket, $source, &$called) {
+                        $called = true;
+
+                        $self
+                            ->object($receivedBucket)
+                                ->isIdenticalTo($bucket)
+                            ->object($receivedBucket->getSource())
+                                ->isIdenticalTo($source);
+
+                        return 42;
+                    }
+                )
+            )
+            ->when($result = $listener->fire($listenerId, $bucket))
+            ->then
+                ->array($result)
+                    ->isEqualTo([42])
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_fire_an_undefined_listenerId()
+    {
+        $this
+            ->given(
+                $source   = new \Mock\Hoa\Event\Listenable(),
+                $ids      = [],
+                $listener = new SUT($source, $ids)
+            )
+            ->exception(function () use ($listener) {
+                $listener->fire('foo', new LUT\Bucket());
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Listens.php b/vendor/hoa/event/Test/Unit/Listens.php
new file mode 100644 (file)
index 0000000..8978c82
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Event as LUT;
+use Hoa\Event\Listens as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Listens.
+ *
+ * Test suite of the listens trait.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Listens extends Test\Unit\Suite
+{
+    public function case_set_listener()
+    {
+        $this
+            ->given(
+                $listenable = new _Listenable(),
+                $listener   = new LUT\Listener($listenable, ['foo'])
+            )
+            ->when($result = $listenable->_setListener($listener))
+            ->then
+                ->variable($result)
+                    ->isNull();
+    }
+
+    public function case_get_listener()
+    {
+        $this
+            ->given(
+                $listenable = new _Listenable(),
+                $listener   = new LUT\Listener($listenable, ['foo']),
+                $listenable->_setListener($listener)
+            )
+            ->when($result = $listenable->_getListener())
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listener);
+    }
+
+    public function case_on()
+    {
+        $this
+            ->given(
+                $listenable = new _Listenable(),
+                $listener   = new LUT\Listener($listenable, ['foo']),
+                $listenable->_setListener($listener),
+                $callable   = function () use (&$called) {
+                    $called = true;
+
+                    return 42;
+                }
+            )
+            ->when($result = $listenable->on('foo', $callable))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($listenable)
+
+            ->when($listenable->doSomethingThatFires())
+            ->then
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_on_unregistered_listener()
+    {
+        $this
+            ->given(
+                $listenable = new _Listenable(),
+                $listener   = new LUT\Listener($listenable, ['foo']),
+                $listenable->_setListener($listener)
+            )
+            ->exception(function () use ($listenable) {
+                $listenable->on('bar', null);
+            })
+                ->isInstanceOf('Hoa\Event\Exception');
+    }
+}
+
+class _Listenable implements LUT\Listenable
+{
+    use SUT;
+
+    public function _setListener(LUT\Listener $listener)
+    {
+        return $this->setListener($listener);
+    }
+
+    public function _getListener()
+    {
+        return $this->getListener();
+    }
+
+    public function doSomethingThatFires()
+    {
+        $this->getListener()->fire('foo', new LUT\Bucket('bar'));
+
+        return;
+    }
+}
diff --git a/vendor/hoa/event/Test/Unit/Source.php b/vendor/hoa/event/Test/Unit/Source.php
new file mode 100644 (file)
index 0000000..1d41880
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Event\Test\Unit;
+
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Event\Test\Unit\Source.
+ *
+ * Test suite of the source interface.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Source extends Test\Unit\Suite
+{
+    public function case_interface()
+    {
+        $this
+            ->when($result = new \Mock\Hoa\Event\Source())
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Event\Source');
+    }
+}
diff --git a/vendor/hoa/event/composer.json b/vendor/hoa/event/composer.json
new file mode 100644 (file)
index 0000000..2935159
--- /dev/null
@@ -0,0 +1,42 @@
+{
+    "name"       : "hoa/event",
+    "description": "The Hoa\\Event library.",
+    "type"       : "library",
+    "keywords"   : ["library", "event", "listener", "observer"],
+    "homepage"   : "https://hoa-project.net/",
+    "license"    : "BSD-3-Clause",
+    "authors"    : [
+        {
+            "name" : "Ivan Enderlin",
+            "email": "ivan.enderlin@hoa-project.net"
+        },
+        {
+            "name"    : "Hoa community",
+            "homepage": "https://hoa-project.net/"
+        }
+    ],
+    "support": {
+        "email" : "support@hoa-project.net",
+        "irc"   : "irc://chat.freenode.net/hoaproject",
+        "forum" : "https://users.hoa-project.net/",
+        "docs"  : "https://central.hoa-project.net/Documentation/Library/Event",
+        "source": "https://central.hoa-project.net/Resource/Library/Event"
+    },
+    "require": {
+        "hoa/consistency": "~1.0",
+        "hoa/exception"  : "~1.0"
+    },
+    "require-dev": {
+        "hoa/test": "~2.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Hoa\\Event\\": "."
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.x-dev"
+        }
+    }
+}
diff --git a/vendor/hoa/exception/.State b/vendor/hoa/exception/.State
new file mode 100644 (file)
index 0000000..a604de4
--- /dev/null
@@ -0,0 +1 @@
+finalized
diff --git a/vendor/hoa/exception/.gitignore b/vendor/hoa/exception/.gitignore
new file mode 100644 (file)
index 0000000..4fbb073
--- /dev/null
@@ -0,0 +1,2 @@
+/vendor/
+/composer.lock
diff --git a/vendor/hoa/exception/CHANGELOG.md b/vendor/hoa/exception/CHANGELOG.md
new file mode 100644 (file)
index 0000000..5cdd72e
--- /dev/null
@@ -0,0 +1,30 @@
+# 1.17.01.16
+
+  * Quality: Happy new year! (Ivan Enderlin, 2017-01-16T08:52:04+01:00)
+
+# 1.16.11.08
+
+  * Documentation: New `README.md` file. (Ivan Enderlin, 2016-10-19T16:31:55+02:00)
+  * Documentation: Update `support` properties. (Ivan Enderlin, 2016-10-05T20:39:14+02:00)
+
+# 1.16.01.11
+
+  * Quality: Drop PHP5.4. (Ivan Enderlin, 2016-01-11T09:15:26+01:00)
+  * Quality: Run devtools:cs. (Ivan Enderlin, 2016-01-09T09:01:35+01:00)
+  * Core: Remove `Hoa\Core`. (Ivan Enderlin, 2016-01-09T08:16:03+01:00)
+  * Consistency: Use `Hoa\Consistency`. (Ivan Enderlin, 2015-12-08T11:11:27+01:00)
+
+# 0.15.11.23
+
+  * Fix phpDoc and a mistake on a static call. (Metalaka, 2015-11-21T17:44:35+01:00)
+  * Add a `.gitignore` file. (Metalaka, 2015-11-21T17:39:21+01:00)
+  * Test: Add test cases for the uncaught handler. (Ivan Enderlin, 2015-11-18T21:48:20+01:00)
+  * Idle: Add uncaught handler. (Ivan Enderlin, 2015-11-18T21:47:40+01:00)
+  * README: Add a better description and new usages. (Ivan Enderlin, 2015-11-18T21:36:03+01:00)
+  * Test: Write test suite of `Hoa\Exception\Group`. (Ivan Enderlin, 2015-11-18T08:28:04+01:00)
+  * Test: Write test suite of `Hoa\Exception\Error`. (Ivan Enderlin, 2015-11-17T22:30:14+01:00)
+  * Test: Write test suite of `…\Exception\Exception`. (Ivan Enderlin, 2015-11-17T22:03:31+01:00)
+  * Test: Write test suite of `Hoa\Exception\Idle`. (Ivan Enderlin, 2015-11-17T21:41:07+01:00)
+  * Split from `Hoa\Core`. (Ivan Enderlin, 2015-11-13T08:58:45+01:00)
+
+(first snapshot)
diff --git a/vendor/hoa/exception/Error.php b/vendor/hoa/exception/Error.php
new file mode 100644 (file)
index 0000000..898aaf8
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception;
+
+/**
+ * Class \Hoa\Exception\Error.
+ *
+ * This exception is the equivalent representation of PHP errors.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Error extends Exception
+{
+    /**
+     * Constructor.
+     *
+     * @param   string  $message    Message.
+     * @param   int     $code       Code (the ID).
+     * @param   string  $file       File.
+     * @param   int     $line       Line.
+     * @param   array   $trace      Trace.
+     */
+    public function __construct(
+        $message,
+        $code,
+        $file,
+        $line,
+        array $trace = []
+    ) {
+        $this->file   = $file;
+        $this->line   = $line;
+        $this->_trace = $trace;
+
+        parent::__construct($message, $code);
+
+        return;
+    }
+
+    /**
+     * Enable error handler: Transform PHP error into `\Hoa\Exception\Error`.
+     *
+     * @param   bool  $enable    Enable.
+     * @return  mixed
+     */
+    public static function enableErrorHandler($enable = true)
+    {
+        if (false === $enable) {
+            return restore_error_handler();
+        }
+
+        return set_error_handler(
+            function ($no, $str, $file = null, $line = null, $ctx = null) {
+                if (0 === ($no & error_reporting())) {
+                    return;
+                }
+
+                $trace = debug_backtrace();
+                array_shift($trace);
+                array_shift($trace);
+
+                throw new Error($str, $no, $file, $line, $trace);
+            }
+        );
+    }
+}
diff --git a/vendor/hoa/exception/Exception.php b/vendor/hoa/exception/Exception.php
new file mode 100644 (file)
index 0000000..23f95fb
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception;
+
+use Hoa\Consistency;
+use Hoa\Event;
+
+/**
+ * Class \Hoa\Exception\Exception.
+ *
+ * Each exception must extend \Hoa\Exception\Exception.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends Idle implements Event\Source
+{
+    /**
+     * Create an exception.
+     * An exception is built with a formatted message, a code (an ID), and an
+     * array that contains the list of formatted string for the message. If
+     * chaining, we can add a previous exception.
+     *
+     * @param   string      $message      Formatted message.
+     * @param   int         $code         Code (the ID).
+     * @param   array       $arguments    Arguments to format message.
+     * @param   \Throwable  $previous     Previous exception in chaining.
+     */
+    public function __construct(
+        $message,
+        $code      = 0,
+        $arguments = [],
+        $previous  = null
+    ) {
+        parent::__construct($message, $code, $arguments, $previous);
+
+        if (false === Event::eventExists('hoa://Event/Exception')) {
+            Event::register('hoa://Event/Exception', __CLASS__);
+        }
+
+        $this->send();
+
+        return;
+    }
+
+    /**
+     * Send the exception on hoa://Event/Exception.
+     *
+     * @return  void
+     */
+    public function send()
+    {
+        Event::notify(
+            'hoa://Event/Exception',
+            $this,
+            new Event\Bucket($this)
+        );
+
+        return;
+    }
+}
+
+/**
+ * Flex entity.
+ */
+Consistency::flexEntity('Hoa\Exception\Exception');
diff --git a/vendor/hoa/exception/Group.php b/vendor/hoa/exception/Group.php
new file mode 100644 (file)
index 0000000..e5dee37
--- /dev/null
@@ -0,0 +1,283 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception;
+
+/**
+ * Class \Hoa\Exception\Group.
+ *
+ * This is an exception that contains a group of exceptions.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Group extends Exception implements \ArrayAccess, \IteratorAggregate, \Countable
+{
+    /**
+     * All exceptions (stored in a stack for transactions).
+     *
+     * @var \SplStack
+     */
+    protected $_group = null;
+
+
+
+    /**
+     * Create an exception.
+     *
+     * @param   string      $message      Formatted message.
+     * @param   int         $code         Code (the ID).
+     * @param   array       $arguments    Arguments to format message.
+     * @param   \Exception  $previous     Previous exception in chaining.
+     */
+    public function __construct(
+        $message,
+        $code                = 0,
+        $arguments           = [],
+        \Exception $previous = null
+    ) {
+        parent::__construct($message, $code, $arguments, $previous);
+        $this->_group = new \SplStack();
+        $this->beginTransaction();
+
+        return;
+    }
+
+    /**
+     * Raise an exception as a string.
+     *
+     * @param   bool    $previous    Whether raise previous exception if exists.
+     * @return  string
+     */
+    public function raise($previous = false)
+    {
+        $out = parent::raise($previous);
+
+        if (0 >= count($this)) {
+            return $out;
+        }
+
+        $out .= "\n\n" . 'Contains the following exceptions:';
+
+        foreach ($this as $exception) {
+            $out .=
+                "\n\n" . '  • ' .
+                str_replace(
+                    "\n",
+                    "\n" . '    ',
+                    $exception->raise($previous)
+                );
+        }
+
+        return $out;
+    }
+
+    /**
+     * Begin a transaction.
+     *
+     * @return  \Hoa\Exception\Group
+     */
+    public function beginTransaction()
+    {
+        $this->_group->push(new \ArrayObject());
+
+        return $this;
+    }
+
+    /**
+     * Rollback a transaction.
+     *
+     * @return  \Hoa\Exception\Group
+     */
+    public function rollbackTransaction()
+    {
+        if (1 >= count($this->_group)) {
+            return $this;
+        }
+
+        $this->_group->pop();
+
+        return $this;
+    }
+
+    /**
+     * Commit a transaction.
+     *
+     * @return  \Hoa\Exception\Group
+     */
+    public function commitTransaction()
+    {
+        if (false === $this->hasUncommittedExceptions()) {
+            $this->_group->pop();
+
+            return $this;
+        }
+
+        foreach ($this->_group->pop() as $index => $exception) {
+            $this[$index] = $exception;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Check if there is uncommitted exceptions.
+     *
+     * @return  bool
+     */
+    public function hasUncommittedExceptions()
+    {
+        return
+            1 < count($this->_group) &&
+            0 < count($this->_group->top());
+    }
+
+    /**
+     * Check if an index in the group exists.
+     *
+     * @param   mixed  $index    Index.
+     * @return  bool
+     */
+    public function offsetExists($index)
+    {
+        foreach ($this->_group as $group) {
+            if (isset($group[$index])) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Get an exception from the group.
+     *
+     * @param   mixed  $index    Index.
+     * @return  Exception
+     */
+    public function offsetGet($index)
+    {
+        foreach ($this->_group as $group) {
+            if (isset($group[$index])) {
+                return $group[$index];
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Set an exception in the group.
+     *
+     * @param   mixed       $index        Index.
+     * @param   Exception  $exception    Exception.
+     * @return  void
+     */
+    public function offsetSet($index, $exception)
+    {
+        if (!($exception instanceof \Exception)) {
+            return null;
+        }
+
+        $group = $this->_group->top();
+
+        if (null === $index ||
+            true === is_int($index)) {
+            $group[] = $exception;
+        } else {
+            $group[$index] = $exception;
+        }
+
+        return;
+    }
+
+    /**
+     * Remove an exception in the group.
+     *
+     * @param   mixed  $index    Index.
+     * @return  void
+     */
+    public function offsetUnset($index)
+    {
+        foreach ($this->_group as $group) {
+            if (isset($group[$index])) {
+                unset($group[$index]);
+            }
+        }
+
+        return;
+    }
+
+    /**
+     * Get committed exceptions in the group.
+     *
+     * @return  \ArrayObject
+     */
+    public function getExceptions()
+    {
+        return $this->_group->bottom();
+    }
+
+    /**
+     * Get an iterator over all exceptions (committed or not).
+     *
+     * @return  \ArrayIterator
+     */
+    public function getIterator()
+    {
+        return $this->getExceptions()->getIterator();
+    }
+
+    /**
+     * Count the number of committed exceptions.
+     *
+     * @return  int
+     */
+    public function count()
+    {
+        return count($this->getExceptions());
+    }
+
+    /**
+     * Count the stack size, i.e. the number of opened transactions.
+     *
+     * @return  int
+     */
+    public function getStackSize()
+    {
+        return count($this->_group);
+    }
+}
diff --git a/vendor/hoa/exception/Idle.php b/vendor/hoa/exception/Idle.php
new file mode 100644 (file)
index 0000000..a942354
--- /dev/null
@@ -0,0 +1,312 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception;
+
+/**
+ * Class \Hoa\Exception\Idle.
+ *
+ * `\Hoa\Exception\Idle` is the mother exception class of libraries. The only
+ * difference between `\Hoa\Exception\Idle` and its directly child
+ * `\Hoa\Exception` is that the latter fires events after beeing constructed.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Idle extends \Exception
+{
+    /**
+     * Delay processing on arguments.
+     *
+     * @var array
+     */
+    protected $_tmpArguments = null;
+
+    /**
+     * Arguments to format message.
+     *
+     * @var array
+     */
+    protected $_arguments    = null;
+
+    /**
+     * Backtrace.
+     *
+     * @var array
+     */
+    protected $_trace        = null;
+
+    /**
+     * Previous.
+     *
+     * @var \Exception
+     */
+    protected $_previous     = null;
+
+    /**
+     * Original message.
+     *
+     * @var string
+     */
+    protected $_rawMessage   = null;
+
+
+
+    /**
+     * Create an exception.
+     * An exception is built with a formatted message, a code (an ID) and an
+     * array that contains the list of formatted strings for the message. If
+     * chaining, we can add a previous exception.
+     *
+     * @param   string      $message      Formatted message.
+     * @param   int         $code         Code (the ID).
+     * @param   array       $arguments    Arguments to format message.
+     * @param   \Exception  $previous     Previous exception in chaining.
+     */
+    public function __construct(
+        $message,
+        $code = 0,
+        $arguments = [],
+        \Exception $previous = null
+    ) {
+        $this->_tmpArguments = $arguments;
+        parent::__construct($message, $code, $previous);
+        $this->_rawMessage   = $message;
+        $this->message       = @vsprintf($message, $this->getArguments());
+
+        return;
+    }
+
+    /**
+     * Get the backtrace.
+     * Do not use \Exception::getTrace() any more.
+     *
+     * @return  array
+     */
+    public function getBacktrace()
+    {
+        if (null === $this->_trace) {
+            $this->_trace = $this->getTrace();
+        }
+
+        return $this->_trace;
+    }
+
+    /**
+     * Get previous.
+     * Do not use \Exception::getPrevious() any more.
+     *
+     * @return  \Exception
+     */
+    public function getPreviousThrow()
+    {
+        if (null === $this->_previous) {
+            $this->_previous = $this->getPrevious();
+        }
+
+        return $this->_previous;
+    }
+
+    /**
+     * Get arguments for the message.
+     *
+     * @return  array
+     */
+    public function getArguments()
+    {
+        if (null === $this->_arguments) {
+            $arguments = $this->_tmpArguments;
+
+            if (!is_array($arguments)) {
+                $arguments = [$arguments];
+            }
+
+            foreach ($arguments as &$value) {
+                if (null === $value) {
+                    $value = '(null)';
+                }
+            }
+
+            $this->_arguments = $arguments;
+            unset($this->_tmpArguments);
+        }
+
+        return $this->_arguments;
+    }
+
+    /**
+     * Get the raw message.
+     *
+     * @return  string
+     */
+    public function getRawMessage()
+    {
+        return $this->_rawMessage;
+    }
+
+    /**
+     * Get the message already formatted.
+     *
+     * @return  string
+     */
+    public function getFormattedMessage()
+    {
+        return $this->getMessage();
+    }
+
+    /**
+     * Get the source of the exception (class, method, function, main etc.).
+     *
+     * @return  string
+     */
+    public function getFrom()
+    {
+        $trace = $this->getBacktrace();
+        $from  = '{main}';
+
+        if (!empty($trace)) {
+            $t    = $trace[0];
+            $from = '';
+
+            if (isset($t['class'])) {
+                $from .= $t['class'] . '::';
+            }
+
+            if (isset($t['function'])) {
+                $from .= $t['function'] . '()';
+            }
+        }
+
+        return $from;
+    }
+
+    /**
+     * Raise an exception as a string.
+     *
+     * @param   bool    $previous    Whether raise previous exception if exists.
+     * @return  string
+     */
+    public function raise($previous = false)
+    {
+        $message = $this->getFormattedMessage();
+        $trace   = $this->getBacktrace();
+        $file    = '/dev/null';
+        $line    = -1;
+        $pre     = $this->getFrom();
+
+        if (!empty($trace)) {
+            $file = isset($trace['file']) ? $trace['file'] : null;
+            $line = isset($trace['line']) ? $trace['line'] : null;
+        }
+
+        $pre .= ': ';
+
+        try {
+            $out =
+                $pre . '(' . $this->getCode() . ') ' . $message . "\n" .
+                'in ' . $this->getFile() . ' at line ' .
+                $this->getLine() . '.';
+        } catch (\Exception $e) {
+            $out =
+                $pre . '(' . $this->getCode() . ') ' . $message . "\n" .
+                'in ' . $file . ' around line ' . $line . '.';
+        }
+
+        if (true === $previous &&
+            null !== $previous = $this->getPreviousThrow()) {
+            $out .=
+                "\n\n" . '    ⬇' . "\n\n" .
+                'Nested exception (' . get_class($previous) . '):' . "\n" .
+                ($previous instanceof self
+                    ? $previous->raise(true)
+                    : $previous->getMessage());
+        }
+
+        return $out;
+    }
+
+    /**
+     * Catch uncaught exception (only \Hoa\Exception\Idle and children).
+     *
+     * @param   \Throwable  $exception    The exception.
+     * @return  void
+     * @throws  \Throwable
+     */
+    public static function uncaught($exception)
+    {
+        if (!($exception instanceof self)) {
+            throw $exception;
+        }
+
+        while (0 < ob_get_level()) {
+            ob_end_flush();
+        }
+
+        echo
+            'Uncaught exception (' . get_class($exception) . '):' . "\n" .
+            $exception->raise(true);
+
+        return;
+    }
+
+    /**
+     * String representation of object.
+     *
+     * @return  string
+     */
+    public function __toString()
+    {
+        return $this->raise();
+    }
+
+    /**
+     * Enable uncaught exception handler.
+     * This is restricted to Hoa's exceptions only.
+     *
+     * @param   bool  $enable    Enable.
+     * @return  mixed
+     */
+    public static function enableUncaughtHandler($enable = true)
+    {
+        if (false === $enable) {
+            return restore_exception_handler();
+        }
+
+        return set_exception_handler(function ($exception) {
+            return self::uncaught($exception);
+        });
+    }
+}
diff --git a/vendor/hoa/exception/README.md b/vendor/hoa/exception/README.md
new file mode 100644 (file)
index 0000000..67cc9e6
--- /dev/null
@@ -0,0 +1,231 @@
+<p align="center">
+  <img src="https://static.hoa-project.net/Image/Hoa.svg" alt="Hoa" width="250px" />
+</p>
+
+---
+
+<p align="center">
+  <a href="https://travis-ci.org/hoaproject/exception"><img src="https://img.shields.io/travis/hoaproject/exception/master.svg" alt="Build status" /></a>
+  <a href="https://coveralls.io/github/hoaproject/exception?branch=master"><img src="https://img.shields.io/coveralls/hoaproject/exception/master.svg" alt="Code coverage" /></a>
+  <a href="https://packagist.org/packages/hoa/exception"><img src="https://img.shields.io/packagist/dt/hoa/exception.svg" alt="Packagist" /></a>
+  <a href="https://hoa-project.net/LICENSE"><img src="https://img.shields.io/packagist/l/hoa/exception.svg" alt="License" /></a>
+</p>
+<p align="center">
+  Hoa is a <strong>modular</strong>, <strong>extensible</strong> and
+  <strong>structured</strong> set of PHP libraries.<br />
+  Moreover, Hoa aims at being a bridge between industrial and research worlds.
+</p>
+
+# Hoa\Exception
+
+[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
+[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
+[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Exception)
+[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/exception)
+
+This library allows to use advanced exceptions. It provides generic exceptions
+(that are sent over the `hoa://Event/Exception` event channel), idle exceptions
+(that are not sent over an event channel), uncaught exception handlers, errors
+to exceptions handler and group of exceptions (with transactions).
+
+[Learn more](https://central.hoa-project.net/Documentation/Library/Exception).
+
+## Installation
+
+With [Composer](https://getcomposer.org/), to include this library into
+your dependencies, you need to
+require [`hoa/exception`](https://packagist.org/packages/hoa/exception):
+
+```sh
+$ composer require hoa/exception '~1.0'
+```
+
+For more installation procedures, please read [the Source
+page](https://hoa-project.net/Source.html).
+
+## Testing
+
+Before running the test suites, the development dependencies must be installed:
+
+```sh
+$ composer install
+```
+
+Then, to run all the test suites:
+
+```sh
+$ vendor/bin/hoa test:run
+```
+
+For more information, please read the [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html).
+
+## Quick usage
+
+We propose a quick overview of how to use generic exceptions, how to listen all
+thrown exceptions through events and how to use group of exceptions.
+
+### Generic exceptions
+
+An exception is constitued of:
+  * A message,
+  * A code (optional),
+  * A list of arguments for the message (à la `printf`, optional),
+  * A previous exception (optional).
+
+Thus, the following example builds an exception:
+
+```php
+$exception = new Hoa\Exception\Exception('Hello %s!', 0, 'world');
+```
+
+The exception message will be: `Hello world!`. The “raise” message (with all
+information, not only the message) is:
+
+```
+{main}: (0) Hello world!
+in … at line ….
+```
+
+Previous exceptions are shown too, for instance:
+
+```php
+$previous  = new Hoa\Exception\Exception('Hello previous.');
+$exception = new Hoa\Exception\Exception('Hello %s!', 0, 'world', $previous);
+
+echo $exception->raise(true);
+
+/**
+ * Will output:
+ *     {main}: (0) Hello world!
+ *     in … at line ….
+ *     
+ *         ⬇
+ *     
+ *     Nested exception (Hoa\Exception\Exception):
+ *     {main}: (0) Hello previous.
+ *     in … at line ….
+ */
+```
+
+### Listen exceptions through events
+
+Most exceptions in Hoa extend `Hoa\Exception\Exception`, which fire themselves
+on the `hoa://Event/Exception` event channel (please, see [the `Hoa\Event`
+library](http://central.hoa-project.net/Resource/Library/Event)). Consequently,
+we can listen for all exceptions that are thrown in the application by writing:
+
+```php
+Hoa\Event\Event::getEvent('hoa://Event/Exception')->attach(
+    function (Hoa\Event\Bucket $bucket) {
+        $exception = $bucket->getData();
+        // …
+    }
+);
+```
+
+Only the `Hoa\Exception\Idle` exceptions are not fired on the channel event.
+
+### Group and transactions
+
+Groups of exceptions are represented by the `Hoa\Exception\Group`. A group is an
+exception that contains one or many exceptions. A transactional API is provided
+to add more exceptions in the group with the following methods:
+  * `beginTransaction` to start a transaction,
+  * `rollbackTransaction` to remove all newly added exceptions since
+    `beginTransaction` call,
+  * `commitTransaction` to merge all newly added exceptions in the previous
+    transaction,
+  * `hasUncommittedExceptions` to check whether they are pending exceptions or
+    not.
+
+For instance, if an exceptional behavior is due to several reasons, a group of
+exceptions can be thrown instead of one exception. Group can be nested too,
+which is useful to represent a tree of exceptions. Thus:
+
+```php
+// A group of exceptions.
+$group           = new Hoa\Exception\Group('Failed because of several reasons.');
+$group['first']  = new Hoa\Exception\Exception('First reason');
+$group['second'] = new Hoa\Exception\Exception('Second reason');
+
+// Can nest another group.
+$group['third']           = new Hoa\Exception\Group('Third reason');
+$group['third']['fourth'] = new Hoa\Exception\Exception('Fourth reason');
+
+echo $group->raise(true);
+
+/**
+ * Will output:
+ *     {main}: (0) Failed because of several reasons.
+ *     in … at line ….
+ *     
+ *     Contains the following exceptions:
+ *     
+ *       • {main}: (0) First reason
+ *         in … at line ….
+ *     
+ *       • {main}: (0) Second reason
+ *         in … at line ….
+ *     
+ *       • {main}: (0) Third reason
+ *         in … at line ….
+ *         
+ *         Contains the following exceptions:
+ *         
+ *           • {main}: (0) Fourth reason
+ *             in … at line ….
+ */
+```
+
+The following example uses a transaction to add new exceptions in the group:
+
+```php
+$group   = new Hoa\Exception\Group('Failed because of several reasons.');
+$group[] = new Hoa\Exception\Exception('Always present.');
+
+$group->beginTransaction();
+
+$group[] = new Hoa\Exception\Exception('Might be present.');
+
+if (true === $condition) {
+    $group->commitTransaction();
+} else {
+    $group->rollbackTransaction();
+}
+```
+
+## Documentation
+
+The
+[hack book of `Hoa\Exception`](https://central.hoa-project.net/Documentation/Library/Exception)
+contains detailed information about how to use this library and how it works.
+
+To generate the documentation locally, execute the following commands:
+
+```sh
+$ composer require --dev hoa/devtools
+$ vendor/bin/hoa devtools:documentation --open
+```
+
+More documentation can be found on the project's website:
+[hoa-project.net](https://hoa-project.net/).
+
+## Getting help
+
+There are mainly two ways to get help:
+
+  * On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
+    IRC channel,
+  * On the forum at [users.hoa-project.net](https://users.hoa-project.net).
+
+## Contribution
+
+Do you want to contribute? Thanks! A detailed [contributor
+guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
+everything you need to know.
+
+## License
+
+Hoa is under the New BSD License (BSD-3-Clause). Please, see
+[`LICENSE`](https://hoa-project.net/LICENSE) for details.
diff --git a/vendor/hoa/exception/Test/Unit/Error.php b/vendor/hoa/exception/Test/Unit/Error.php
new file mode 100644 (file)
index 0000000..e4f3702
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception\Test\Unit;
+
+use Hoa\Exception\Error as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Exception\Test\Unit\Error.
+ *
+ * Test suite of the error class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Error extends Test\Unit\Suite
+{
+    public function case_is_an_exception()
+    {
+        $this
+            ->when($result = new SUT('foo', 42, '/hoa/flatland', 153))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Exception\Exception');
+    }
+
+    public function case_get_message()
+    {
+        $this
+            ->given($exception = new SUT('foo', 42, '/hoa/flatland', 153))
+            ->when($result = $exception->raise())
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        '{main}: (42) foo' . "\n" .
+                        'in /hoa/flatland at line 153.'
+                    );
+    }
+
+    public function case_disable_error_handler()
+    {
+        $this
+            ->given(
+                $this->function->restore_error_handler = function () use (&$called) {
+                    $called = true;
+
+                    return null;
+                }
+            )
+            ->when($result = SUT::enableErrorHandler(false))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_enable_error_handler()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $this->function->set_error_handler = function ($handler) use ($self, &$called) {
+                    $called = true;
+
+                    $self
+                        ->object($handler)
+                            ->isInstanceOf('Closure')
+                        ->let($reflection = new \ReflectionObject($handler))
+                        ->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
+                            ->hasSize(5)
+                        ->string($invokeParameters[0]->getName())
+                            ->isEqualTo('no')
+                        ->string($invokeParameters[1]->getName())
+                            ->isEqualTo('str')
+                        ->string($invokeParameters[2]->getName())
+                            ->isEqualTo('file')
+                        ->boolean($invokeParameters[2]->isOptional())
+                            ->isTrue()
+                        ->string($invokeParameters[3]->getName())
+                            ->isEqualTo('line')
+                        ->boolean($invokeParameters[3]->isOptional())
+                            ->isTrue()
+                        ->string($invokeParameters[4]->getName())
+                            ->isEqualTo('ctx')
+                        ->boolean($invokeParameters[4]->isOptional())
+                            ->isTrue();
+
+                    return null;
+                }
+            )
+            ->when($result = SUT::enableErrorHandler())
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_error_handler()
+    {
+        $this
+            ->given(SUT::enableErrorHandler())
+            ->exception(function () {
+                ++$i;
+            })
+                ->isInstanceOf('Hoa\Exception\Error')
+                ->hasMessage('Undefined variable: i');
+    }
+}
diff --git a/vendor/hoa/exception/Test/Unit/Exception.php b/vendor/hoa/exception/Test/Unit/Exception.php
new file mode 100644 (file)
index 0000000..d5cb492
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception\Test\Unit;
+
+use Hoa\Event;
+use Hoa\Exception\Exception as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Exception\Test\Unit\Exception.
+ *
+ * Test suite of the exception class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Exception extends Test\Unit\Suite
+{
+    public function case_is_an_idle_exception()
+    {
+        $this
+            ->when($result = new SUT('foo'))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Exception\Idle');
+    }
+
+    public function case_event_is_registered()
+    {
+        $this
+            ->given(new SUT('foo'))
+            ->when($result = Event::eventExists('hoa://Event/Exception'))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_event_is_sent()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                Event::getEvent('hoa://Event/Exception')->attach(
+                    function (Event\Bucket $bucket) use ($self, &$called) {
+                        $called = true;
+
+                        $self
+                            ->object($bucket->getSource())
+                                ->isInstanceOf('Hoa\Exception\Exception')
+                            ->string($bucket->getSource()->getMessage())
+                                ->isEqualTo('foo')
+                            ->object($bucket->getData())
+                                ->isIdenticalTo($bucket->getSource());
+                    }
+                )
+            )
+            ->when(new SUT('foo'))
+            ->then
+                ->boolean($called)
+                    ->isTrue();
+    }
+}
diff --git a/vendor/hoa/exception/Test/Unit/Group.php b/vendor/hoa/exception/Test/Unit/Group.php
new file mode 100644 (file)
index 0000000..45f371b
--- /dev/null
@@ -0,0 +1,610 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception\Test\Unit;
+
+use Hoa\Exception\Group as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Exception\Test\Unit\Group.
+ *
+ * Test suite of the group class.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Group extends Test\Unit\Suite
+{
+    public function case_is_an_exception_arrayaccess_iteratoraggregate_countable()
+    {
+        $this
+            ->when($result = new SUT('foo'))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Hoa\Exception\Exception')
+                    ->isInstanceOf('ArrayAccess')
+                    ->isInstanceOf('IteratorAggregate')
+                    ->isInstanceOf('Countable');
+    }
+
+    public function case_constructor()
+    {
+        $this
+            ->given(
+                $message   = 'foo %s %d %s',
+                $code      = 7,
+                $arguments = ['arg', 42, null],
+                $previous  = new SUT('previous')
+            )
+            ->when($result = new SUT($message, $code, $arguments, $previous), $line = __LINE__)
+            ->then
+                ->string($result->getMessage())
+                    ->isEqualTo('foo arg 42 (null)')
+                ->integer($result->getCode())
+                    ->isEqualTo(7)
+                ->array($result->getArguments())
+                    ->isEqualTo(['arg', 42, '(null)'])
+                ->object($result->getPreviousThrow())
+                    ->isIdenticalTo($previous)
+                ->boolean($result->hasUncommittedExceptions())
+                    ->isFalse();
+    }
+
+    public function case_raise_zero_exception()
+    {
+        $this
+            ->given($group = new SUT('foo'), $line = __LINE__)
+            ->when($result = $group->raise())
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $line . '.'
+                    );
+    }
+
+    public function case_raise_one_exception()
+    {
+        $this
+            ->given(
+                $exception1 = new SUT('bar'), $barLine = __LINE__,
+                $group      = new SUT('foo'), $fooLine = __LINE__,
+                $group[]    = $exception1
+            )
+            ->when($result = $group->raise())
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
+                        'Contains the following exceptions:' . "\n\n" .
+                        '  • ' . __METHOD__ . '(): (0) bar' . "\n" .
+                        '    in ' . __FILE__ . ' at line ' . $barLine . '.'
+                    );
+    }
+
+    public function case_raise_more_exceptions()
+    {
+        $this
+            ->given(
+                $exception1 = new SUT('bar'), $barLine = __LINE__,
+                $exception2 = new SUT('baz'), $bazLine = __LINE__,
+                $group      = new SUT('foo'), $fooLine = __LINE__,
+                $group[]    = $exception1,
+                $group[]    = $exception2
+            )
+            ->when($result = $group->raise())
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $fooLine . '.' . "\n\n" .
+                        'Contains the following exceptions:' . "\n\n" .
+                        '  • ' . __METHOD__ . '(): (0) bar' . "\n" .
+                        '    in ' . __FILE__ . ' at line ' . $barLine . '.' . "\n\n" .
+                        '  • ' . __METHOD__ . '(): (0) baz' . "\n" .
+                        '    in ' . __FILE__ . ' at line ' . $bazLine . '.'
+                    );
+    }
+
+    public function case_begin_transaction()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $oldStackSize = $group->getStackSize()
+            )
+            ->when(
+                $result    = $group->beginTransaction(),
+                $stackSize = $group->getStackSize()
+            )
+            ->then
+                ->integer($oldStackSize)
+                    ->isEqualTo(1)
+                ->object($result)
+                    ->isIdenticalTo($group)
+                ->integer($stackSize)
+                    ->isEqualTo($oldStackSize + 1);
+    }
+
+    public function case_rollback_transaction_with_an_empty_stack()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $oldStackSize = $group->getStackSize()
+            )
+            ->when(
+                $result    = $group->rollbackTransaction(),
+                $stackSize = $group->getStackSize()
+            )
+            ->then
+                ->integer($oldStackSize)
+                    ->isEqualTo(1)
+                ->object($result)
+                    ->isIdenticalTo($group)
+                ->integer($stackSize)
+                    ->isEqualTo($oldStackSize);
+    }
+
+    public function case_rollback_transaction()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $oldStackSize = $group->getStackSize(),
+                $group->rollbackTransaction()
+            )
+            ->when(
+                $result    = $group->rollbackTransaction(),
+                $stackSize = $group->getStackSize()
+            )
+            ->then
+                ->integer($oldStackSize)
+                    ->isEqualTo(3)
+                ->object($result)
+                    ->isIdenticalTo($group)
+                ->integer($stackSize)
+                    ->isEqualTo($oldStackSize - 2);
+    }
+
+    public function case_commit_transaction_with_an_empty_stack()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $oldCount     = count($group),
+                $oldStackSize = $group->getStackSize()
+            )
+            ->when(
+                $result    = $group->commitTransaction(),
+                $count     = count($group),
+                $stackSize = $group->getStackSize()
+            )
+            ->then
+                ->integer($oldCount)
+                    ->isEqualTo(0)
+                ->integer($oldStackSize)
+                    ->isEqualTo(2)
+                ->object($result)
+                    ->isIdenticalTo($group)
+                ->integer($count)
+                    ->isEqualTo($oldCount)
+                ->integer($stackSize)
+                    ->isEqualTo($oldStackSize - 1);
+    }
+
+    public function case_commit_transaction()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $exception1   = new SUT('bar'),
+                $exception2   = new SUT('baz'),
+                $group[]      = $exception1,
+                $group[]      = $exception2,
+                $oldCount     = count($group),
+                $oldStackSize = $group->getStackSize()
+            )
+            ->when(
+                $result    = $group->commitTransaction(),
+                $count     = count($group),
+                $stackSize = $group->getStackSize()
+            )
+            ->then
+                ->integer($oldCount)
+                    ->isEqualTo(0)
+                ->integer($oldStackSize)
+                    ->isEqualTo(2)
+                ->object($result)
+                    ->isIdenticalTo($group)
+                ->integer($count)
+                    ->isEqualTo($oldCount + 2)
+                ->integer($stackSize)
+                    ->isEqualTo($oldStackSize - 1)
+                ->array(iterator_to_array($group->getIterator()))
+                    ->isEqualTo([
+                        0 => $exception1,
+                        1 => $exception2
+                    ]);
+    }
+
+    public function case_has_uncommitted_exceptions()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group[] = new SUT('bar')
+            )
+            ->when($result = $group->hasUncommittedExceptions())
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_has_no_uncommitted_exceptions()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction()
+            )
+            ->when($result = $group->hasUncommittedExceptions())
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_has_no_uncommitted_exceptions_with_empty_stack()
+    {
+        $this
+            ->given(
+                $group   = new SUT('foo'),
+                $group[] = new SUT('bar')
+            )
+            ->when($result = $group->hasUncommittedExceptions())
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_offset_exists_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($result = $group->offsetExists('bar'))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_offset_does_not_exist_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($result = $group->offsetExists('baz'))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_offset_exists()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($result = $group->offsetExists('bar'))
+            ->then
+                ->boolean($result)
+                    ->isTrue();
+    }
+
+    public function case_offset_does_not_exist()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($result = $group->offsetExists('baz'))
+            ->then
+                ->boolean($result)
+                    ->isFalse();
+    }
+
+    public function case_offset_get_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $group['bar'] = $exception1
+            )
+            ->when($result = $group->offsetGet('bar'))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_offset_get_does_not_exist_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $group['bar'] = $exception1
+            )
+            ->when($result = $group->offsetGet('baz'))
+            ->then
+                ->variable($result)
+                    ->isNull();
+    }
+
+    public function case_offset_get()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $exception1   = new SUT('bar'),
+                $group['bar'] = $exception1
+            )
+            ->when($result = $group->offsetGet('bar'))
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_offset_get_does_not_exist()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $exception1   = new SUT('bar'),
+                $group['bar'] = $exception1
+            )
+            ->when($result = $group->offsetGet('baz'))
+            ->then
+                ->variable($result)
+                    ->isNull();
+    }
+
+    public function case_offset_set_not_an_exception()
+    {
+        $this
+            ->given($group = new SUT('foo'))
+            ->when($group->offsetSet('bar', new \StdClass()))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isFalse();
+    }
+
+    public function case_offset_set()
+    {
+        $this
+            ->given(
+                $group      = new SUT('foo'),
+                $exception1 = new SUT('bar')
+            )
+            ->when($result = $group->offsetExists('bar'))
+            ->then
+                ->boolean($result)
+                    ->isFalse()
+
+            ->when($group->offsetSet('bar', $exception1))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isTrue()
+                ->object($group->offsetGet('bar'))
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_offset_set_with_a_null_index()
+    {
+        $this
+            ->given(
+                $group      = new SUT('foo'),
+                $exception1 = new SUT('bar')
+            )
+            ->when($group->offsetSet(null, $exception1))
+            ->then
+                ->boolean($group->offsetExists(0))
+                    ->isTrue()
+                ->object($group->offsetGet(0))
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_offset_set_with_an_integer_index()
+    {
+        $this
+            ->given(
+                $group      = new SUT('foo'),
+                $exception1 = new SUT('bar')
+            )
+            ->when($group->offsetSet(42, $exception1))
+            ->then
+                ->boolean($group->offsetExists(42))
+                    ->isFalse()
+                ->boolean($group->offsetExists(0))
+                    ->isTrue()
+                ->object($group->offsetGet(0))
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_offset_unset_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($group->offsetUnset('bar'))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isFalse();
+    }
+
+    public function case_offset_unset_does_not_exist_with_no_uncommited_exceptions()
+    {
+        $this
+            ->given($group = new SUT('foo'))
+            ->when($group->offsetUnset('bar'))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isFalse();
+    }
+
+    public function case_offset_unset()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction(),
+                $group['bar'] = new SUT('bar')
+            )
+            ->when($result = $group->offsetUnset('bar'))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isFalse();
+    }
+
+    public function case_offset_unset_does_not_exist()
+    {
+        $this
+            ->given(
+                $group = new SUT('foo'),
+                $group->beginTransaction(),
+                $group->beginTransaction()
+            )
+            ->when($result = $group->offsetUnset('bar'))
+            ->then
+                ->boolean($group->offsetExists('bar'))
+                    ->isFalse();
+    }
+
+    public function case_get_exceptions()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $exception2   = new SUT('baz'),
+                $group['bar'] = $exception1,
+                $group->beginTransaction(),
+                $group['baz'] = $exception2
+            )
+            ->when($result = $group->getExceptions())
+            ->then
+                ->object($result)
+                    ->isInstanceOf('ArrayObject')
+                ->object($result['bar'])
+                    ->isIdenticalTo($exception1);
+    }
+
+    public function case_get_iterator()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $group['bar'] = $exception1
+            )
+            ->when($result = $group->getIterator())
+            ->then
+                ->object($result)
+                    ->isInstanceOf('ArrayIterator')
+                ->array(iterator_to_array($result))
+                    ->isEqualTo([
+                        'bar' => $exception1
+                    ]);
+    }
+
+    public function case_count()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $exception2   = new SUT('baz'),
+                $group['bar'] = $exception1,
+                $group->beginTransaction(),
+                $group['baz'] = $exception2
+            )
+            ->when($result = count($group))
+            ->then
+                ->integer($result)
+                    ->isEqualTo(1);
+    }
+
+    public function get_get_stack_size()
+    {
+        $this
+            ->given(
+                $group        = new SUT('foo'),
+                $exception1   = new SUT('bar'),
+                $exception2   = new SUT('baz'),
+                $group['bar'] = $exception1,
+                $group->beginTransaction(),
+                $group['baz'] = $exception2
+            )
+            ->when($result = $group->getStackSize())
+            ->then
+                ->integer($result)
+                    ->isEqualTo(2);
+    }
+}
diff --git a/vendor/hoa/exception/Test/Unit/Idle.php b/vendor/hoa/exception/Test/Unit/Idle.php
new file mode 100644 (file)
index 0000000..df1f46f
--- /dev/null
@@ -0,0 +1,267 @@
+<?php
+
+/**
+ * Hoa
+ *
+ *
+ * @license
+ *
+ * New BSD License
+ *
+ * Copyright © 2007-2017, Hoa community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Hoa nor the names of its contributors may be
+ *       used to endorse or promote products derived from this software without
+ *       specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace Hoa\Exception\Test\Unit;
+
+use Hoa\Exception\Idle as SUT;
+use Hoa\Test;
+
+/**
+ * Class \Hoa\Exception\Test\Unit\Idle.
+ *
+ * Test suite of the idle exception.
+ *
+ * @copyright  Copyright © 2007-2017 Hoa community
+ * @license    New BSD License
+ */
+class Idle extends Test\Unit\Suite
+{
+    public function case_is_a_real_exception()
+    {
+        $this
+            ->when($result = new SUT('foo'))
+            ->then
+                ->object($result)
+                    ->isInstanceOf('Exception');
+    }
+
+    public function case_get_backtrace()
+    {
+        $this
+            ->given($exception = new SUT('foo'))
+            ->when($result = $exception->getBacktrace())
+            ->then
+                ->array($result)
+                    ->hasKey(0)
+                ->array($result[0])
+                    ->hasKey('file')
+                    ->hasKey('line')
+                    ->hasKey('function')
+                    ->hasKey('class')
+                    ->hasKey('type')
+                    ->hasKey('args');
+    }
+
+    public function case_get_previous_throw()
+    {
+        $this
+            ->given(
+                $previous  = new SUT('previous'),
+                $exception = new SUT('foo', 0, [], $previous)
+            )
+            ->when($result = $exception->getPreviousThrow())
+            ->then
+                ->object($result)
+                    ->isIdenticalTo($previous);
+    }
+
+    public function case_get_arguments()
+    {
+        $this
+            ->given($exception = new SUT('foo', 0, ['arg', 42, null]))
+            ->when($result = $exception->getArguments())
+            ->then
+                ->array($result)
+                    ->isEqualTo(['arg', 42, '(null)']);
+    }
+
+    public function case_get_arguments_from_a_string()
+    {
+        $this
+            ->given($exception = new SUT('foo', 0, 'arg'))
+            ->when($result = $exception->getArguments())
+            ->then
+                ->array($result)
+                    ->isEqualTo(['arg']);
+    }
+
+    public function case_get_raw_message()
+    {
+        $this
+            ->given(
+                $message   = 'foo %s',
+                $exception = new SUT($message)
+            )
+            ->when($result = $exception->getRawMessage())
+            ->then
+                ->string($result)
+                    ->isEqualTo($message);
+    }
+
+    public function case_get_formatted_message()
+    {
+        $this
+            ->given(
+                $message   = 'foo %s',
+                $exception = new SUT($message, 0, 'bar')
+            )
+            ->when($result = $exception->getFormattedMessage())
+            ->then
+                ->string($result)
+                    ->isEqualTo($exception->getMessage())
+                    ->isEqualTo('foo bar');
+    }
+
+    public function case_get_from_object()
+    {
+        $this
+            ->given($exception = new SUT('foo'))
+            ->when($result = $exception->getFrom())
+            ->then
+                ->string($result)
+                    ->isEqualTo(__METHOD__ . '()');
+    }
+
+    public function case_raise()
+    {
+        $this
+            ->given($exception = new SUT('foo'), $line = __LINE__)
+            ->when($result = $exception->raise())
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $line . '.'
+                    );
+    }
+
+    public function case_raise_with_previous()
+    {
+        $this
+            ->given(
+                $previous  = new SUT('previous'), $previousLine = __LINE__,
+                $exception = new SUT('foo', 0, [], $previous), $line = __LINE__
+            )
+            ->when($result = $exception->raise(true))
+            ->then
+                ->string($result)
+                    ->isEqualTo(
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $line . '.' . "\n\n" .
+                        '    ⬇' . "\n\n" .
+                        'Nested exception (' . get_class($previous) . '):' . "\n" .
+                        __METHOD__ . '(): (0) previous' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $previousLine . '.'
+                    );
+    }
+
+    public function case_uncaught()
+    {
+        $this
+            ->given(
+                $this->function->ob_get_level = 0,
+                $exception = new SUT('foo'), $line = __LINE__
+            )
+            ->when($result = SUT::uncaught($exception))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->output
+                    ->isEqualTo(
+                        'Uncaught exception (' . get_class($exception) . '):' . "\n" .
+                        __METHOD__ . '(): (0) foo' . "\n" .
+                        'in ' . __FILE__ . ' at line ' . $line . '.'
+                    );
+    }
+
+    public function case_uncaught_not_Hoa()
+    {
+        $this
+            ->exception(function () {
+                SUT::uncaught(new \Exception('foo'));
+            })
+                ->isInstanceOf('Exception')
+            ->output
+                ->isEmpty();
+    }
+
+    public function case_to_string()
+    {
+        $this
+            ->given($exception = new SUT('foo'))
+            ->when($result = $exception->__toString())
+            ->then
+                ->string($result)
+                    ->isEqualTo($exception->raise());
+    }
+
+    public function case_disable_uncaught_handler()
+    {
+        $this
+            ->given(
+                $this->function->restore_exception_handler = function () use (&$called) {
+                    $called = true;
+
+                    return null;
+                }
+            )
+            ->when($result = SUT::enableUncaughtHandler(false))
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+
+    public function case_enable_uncaught_handler()
+    {
+        $self = $this;
+
+        $this
+            ->given(
+                $this->function->set_exception_handler = function ($handler) use ($self, &$called) {
+                    $called = true;
+
+                    $self
+                        ->object($handler)
+                            ->isInstanceOf('Closure')
+                        ->let($reflection = new \ReflectionObject($handler))
+                        ->array($invokeParameters = $reflection->getMethod('__invoke')->getParameters())
+                            ->hasSize(1)
+                        ->string($invokeParameters[0]->getName())
+                            ->isEqualTo('exception');
+
+                    return null;
+                }
+            )
+            ->when($result = SUT::enableUncaughtHandler())
+            ->then
+                ->variable($result)
+                    ->isNull()
+                ->boolean($called)
+                    ->isTrue();
+    }
+}
diff --git a/vendor/hoa/exception/composer.json b/vendor/hoa/exception/composer.json
new file mode 100644 (file)
index 0000000..0751d84
--- /dev/null
@@ -0,0 +1,42 @@
+{
+    "name"       : "hoa/exception",
+    "description": "The Hoa\\Exception library.",
+    "type"       : "library",
+    "keywords"   : ["library", "exception"],
+    "homepage"   : "https://hoa-project.net/",
+    "license"    : "BSD-3-Clause",
+    "authors"    : [
+        {
+            "name" : "Ivan Enderlin",
+            "email": "ivan.enderlin@hoa-project.net"
+        },
+        {
+            "name"    : "Hoa community",
+            "homepage": "https://hoa-project.net/"
+        }
+    ],
+    "support": {
+        "email" : "support@hoa-project.net",
+        "irc"   : "irc://chat.freenode.net/hoaproject",
+        "forum" : "https://users.hoa-project.net/",
+        "docs"  : "https://central.hoa-project.net/Documentation/Library/Exception",
+        "source": "https://central.hoa-project.net/Resource/Library/Exception"
+    },
+    "require": {
+        "hoa/consistency": "~1.0",
+        "hoa/event"      : "~1.0"
+    },
+    "require-dev": {
+        "hoa/test": "~2.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Hoa\\Exception\\": "."
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.x-dev"
+        }
+    }
+}
diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE
new file mode 100644 (file)
index 0000000..45c7017
--- /dev/null
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Paragon Initiative Enterprises
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json
new file mode 100644 (file)
index 0000000..34f1381
--- /dev/null
@@ -0,0 +1,38 @@
+{
+  "name":         "paragonie/random_compat",
+  "description":  "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+  "keywords": [
+    "csprng",
+    "random",
+    "polyfill",
+    "pseudorandom"
+  ],
+  "license":      "MIT",
+  "type":         "library",
+  "authors": [
+    {
+      "name":     "Paragon Initiative Enterprises",
+      "email":    "security@paragonie.com",
+      "homepage": "https://paragonie.com"
+    }
+  ],
+  "support": {
+    "issues":     "https://github.com/paragonie/random_compat/issues",
+    "email":      "info@paragonie.com",
+    "source":     "https://github.com/paragonie/random_compat"
+  },
+  "require": {
+    "php": ">=5.2.0"
+  },
+  "require-dev": {
+    "phpunit/phpunit": "4.*|5.*"
+  },
+  "suggest": {
+    "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+  },
+  "autoload": {
+    "files": [
+      "lib/random.php"
+    ]
+  }
+}
diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey
new file mode 100644 (file)
index 0000000..eb50ebf
--- /dev/null
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
+pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
+-----END PUBLIC KEY-----
diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc
new file mode 100644 (file)
index 0000000..6a1d7f3
--- /dev/null
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2.0.22 (MingW32)
+
+iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
+QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
+1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
+NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
+NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
+JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
+=B6+8
+-----END PGP SIGNATURE-----
diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php
new file mode 100644 (file)
index 0000000..ef24488
--- /dev/null
@@ -0,0 +1,195 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('RandomCompat_strlen')) {
+    if (
+        defined('MB_OVERLOAD_STRING')
+            &&
+        ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING
+    ) {
+        /**
+         * strlen() implementation that isn't brittle to mbstring.func_overload
+         *
+         * This version uses mb_strlen() in '8bit' mode to treat strings as raw
+         * binary rather than UTF-8, ISO-8859-1, etc
+         *
+         * @param string $binary_string
+         *
+         * @throws TypeError
+         *
+         * @return int
+         */
+        function RandomCompat_strlen($binary_string)
+        {
+            if (!is_string($binary_string)) {
+                throw new TypeError(
+                    'RandomCompat_strlen() expects a string'
+                );
+            }
+
+            return (int) mb_strlen($binary_string, '8bit');
+        }
+
+    } else {
+        /**
+         * strlen() implementation that isn't brittle to mbstring.func_overload
+         *
+         * This version just used the default strlen()
+         *
+         * @param string $binary_string
+         *
+         * @throws TypeError
+         *
+         * @return int
+         */
+        function RandomCompat_strlen($binary_string)
+        {
+            if (!is_string($binary_string)) {
+                throw new TypeError(
+                    'RandomCompat_strlen() expects a string'
+                );
+            }
+            return (int) strlen($binary_string);
+        }
+    }
+}
+
+if (!is_callable('RandomCompat_substr')) {
+
+    if (
+        defined('MB_OVERLOAD_STRING')
+            &&
+        ((int) ini_get('mbstring.func_overload')) & MB_OVERLOAD_STRING
+    ) {
+        /**
+         * substr() implementation that isn't brittle to mbstring.func_overload
+         *
+         * This version uses mb_substr() in '8bit' mode to treat strings as raw
+         * binary rather than UTF-8, ISO-8859-1, etc
+         *
+         * @param string $binary_string
+         * @param int $start
+         * @param int|null $length (optional)
+         *
+         * @throws TypeError
+         *
+         * @return string
+         */
+        function RandomCompat_substr($binary_string, $start, $length = null)
+        {
+            if (!is_string($binary_string)) {
+                throw new TypeError(
+                    'RandomCompat_substr(): First argument should be a string'
+                );
+            }
+
+            if (!is_int($start)) {
+                throw new TypeError(
+                    'RandomCompat_substr(): Second argument should be an integer'
+                );
+            }
+
+            if ($length === null) {
+                /**
+                 * mb_substr($str, 0, NULL, '8bit') returns an empty string on
+                 * PHP 5.3, so we have to find the length ourselves.
+                 */
+                /** @var int $length */
+                $length = RandomCompat_strlen($binary_string) - $start;
+            } elseif (!is_int($length)) {
+                throw new TypeError(
+                    'RandomCompat_substr(): Third argument should be an integer, or omitted'
+                );
+            }
+
+            // Consistency with PHP's behavior
+            if ($start === RandomCompat_strlen($binary_string) && $length === 0) {
+                return '';
+            }
+            if ($start > RandomCompat_strlen($binary_string)) {
+                return '';
+            }
+
+            return (string) mb_substr(
+                (string) $binary_string,
+                (int) $start,
+                (int) $length,
+                '8bit'
+            );
+        }
+
+    } else {
+
+        /**
+         * substr() implementation that isn't brittle to mbstring.func_overload
+         *
+         * This version just uses the default substr()
+         *
+         * @param string $binary_string
+         * @param int $start
+         * @param int|null $length (optional)
+         *
+         * @throws TypeError
+         *
+         * @return string
+         */
+        function RandomCompat_substr($binary_string, $start, $length = null)
+        {
+            if (!is_string($binary_string)) {
+                throw new TypeError(
+                    'RandomCompat_substr(): First argument should be a string'
+                );
+            }
+
+            if (!is_int($start)) {
+                throw new TypeError(
+                    'RandomCompat_substr(): Second argument should be an integer'
+                );
+            }
+
+            if ($length !== null) {
+                if (!is_int($length)) {
+                    throw new TypeError(
+                        'RandomCompat_substr(): Third argument should be an integer, or omitted'
+                    );
+                }
+
+                return (string) substr(
+                    (string )$binary_string,
+                    (int) $start,
+                    (int) $length
+                );
+            }
+
+            return (string) substr(
+                (string) $binary_string,
+                (int) $start
+            );
+        }
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php
new file mode 100644 (file)
index 0000000..1b1bbfe
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('RandomCompat_intval')) {
+
+    /**
+     * Cast to an integer if we can, safely.
+     *
+     * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
+     * (non-inclusive), it will sanely cast it to an int. If you it's equal to
+     * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats 
+     * lose precision, so the <= and => operators might accidentally let a float
+     * through.
+     *
+     * @param int|float $number    The number we want to convert to an int
+     * @param bool      $fail_open Set to true to not throw an exception
+     *
+     * @return float|int
+     * @psalm-suppress InvalidReturnType
+     *
+     * @throws TypeError
+     */
+    function RandomCompat_intval($number, $fail_open = false)
+    {
+        if (is_int($number) || is_float($number)) {
+            $number += 0;
+        } elseif (is_numeric($number)) {
+            /** @psalm-suppress InvalidOperand */
+            $number += 0;
+        }
+        /** @var int|float $number */
+
+        if (
+            is_float($number)
+                &&
+            $number > ~PHP_INT_MAX
+                &&
+            $number < PHP_INT_MAX
+        ) {
+            $number = (int) $number;
+        }
+
+        if (is_int($number)) {
+            return (int) $number;
+        } elseif (!$fail_open) {
+            throw new TypeError(
+                'Expected an integer.'
+            );
+        }
+        return $number;
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php
new file mode 100644 (file)
index 0000000..c02c5c8
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!class_exists('Error', false)) {
+    // We can't really avoid making this extend Exception in PHP 5.
+    class Error extends Exception
+    {
+
+    }
+}
+
+if (!class_exists('TypeError', false)) {
+    if (is_subclass_of('Error', 'Exception')) {
+        class TypeError extends Error
+        {
+
+        }
+    } else {
+        class TypeError extends Exception
+        {
+
+        }
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random.php b/vendor/paragonie/random_compat/lib/random.php
new file mode 100644 (file)
index 0000000..36245f5
--- /dev/null
@@ -0,0 +1,225 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * @version 2.0.17
+ * @released 2018-07-04
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!defined('PHP_VERSION_ID')) {
+    // This constant was introduced in PHP 5.2.7
+    $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
+    define(
+        'PHP_VERSION_ID',
+        $RandomCompatversion[0] * 10000
+        + $RandomCompatversion[1] * 100
+        + $RandomCompatversion[2]
+    );
+    $RandomCompatversion = null;
+}
+
+/**
+ * PHP 7.0.0 and newer have these functions natively.
+ */
+if (PHP_VERSION_ID >= 70000) {
+    return;
+}
+
+if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
+    define('RANDOM_COMPAT_READ_BUFFER', 8);
+}
+
+$RandomCompatDIR = dirname(__FILE__);
+
+require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
+require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
+require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
+
+if (!is_callable('random_bytes')) {
+    /**
+     * PHP 5.2.0 - 5.6.x way to implement random_bytes()
+     *
+     * We use conditional statements here to define the function in accordance
+     * to the operating environment. It's a micro-optimization.
+     *
+     * In order of preference:
+     *   1. Use libsodium if available.
+     *   2. fread() /dev/urandom if available (never on Windows)
+     *   3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)
+     *   4. COM('CAPICOM.Utilities.1')->GetRandom()
+     *
+     * See RATIONALE.md for our reasoning behind this particular order
+     */
+    if (extension_loaded('libsodium')) {
+        // See random_bytes_libsodium.php
+        if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
+            require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
+        } elseif (method_exists('Sodium', 'randombytes_buf')) {
+            require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
+        }
+    }
+
+    /**
+     * Reading directly from /dev/urandom:
+     */
+    if (DIRECTORY_SEPARATOR === '/') {
+        // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
+        // way to exclude Windows.
+        $RandomCompatUrandom = true;
+        $RandomCompat_basedir = ini_get('open_basedir');
+
+        if (!empty($RandomCompat_basedir)) {
+            $RandomCompat_open_basedir = explode(
+                PATH_SEPARATOR,
+                strtolower($RandomCompat_basedir)
+            );
+            $RandomCompatUrandom = (array() !== array_intersect(
+                array('/dev', '/dev/', '/dev/urandom'),
+                $RandomCompat_open_basedir
+            ));
+            $RandomCompat_open_basedir = null;
+        }
+
+        if (
+            !is_callable('random_bytes')
+            &&
+            $RandomCompatUrandom
+            &&
+            @is_readable('/dev/urandom')
+        ) {
+            // Error suppression on is_readable() in case of an open_basedir
+            // or safe_mode failure. All we care about is whether or not we
+            // can read it at this point. If the PHP environment is going to
+            // panic over trying to see if the file can be read in the first
+            // place, that is not helpful to us here.
+
+            // See random_bytes_dev_urandom.php
+            require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
+        }
+        // Unset variables after use
+        $RandomCompat_basedir = null;
+    } else {
+        $RandomCompatUrandom = false;
+    }
+
+    /**
+     * mcrypt_create_iv()
+     *
+     * We only want to use mcypt_create_iv() if:
+     *
+     * - random_bytes() hasn't already been defined
+     * - the mcrypt extensions is loaded
+     * - One of these two conditions is true:
+     *   - We're on Windows (DIRECTORY_SEPARATOR !== '/')
+     *   - We're not on Windows and /dev/urandom is readabale
+     *     (i.e. we're not in a chroot jail)
+     * - Special case:
+     *   - If we're not on Windows, but the PHP version is between
+     *     5.6.10 and 5.6.12, we don't want to use mcrypt. It will
+     *     hang indefinitely. This is bad.
+     *   - If we're on Windows, we want to use PHP >= 5.3.7 or else
+     *     we get insufficient entropy errors.
+     */
+    if (
+        !is_callable('random_bytes')
+        &&
+        // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be.
+        (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307)
+        &&
+        // Prevent this code from hanging indefinitely on non-Windows;
+        // see https://bugs.php.net/bug.php?id=69833
+        (
+            DIRECTORY_SEPARATOR !== '/' ||
+            (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)
+        )
+        &&
+        extension_loaded('mcrypt')
+    ) {
+        // See random_bytes_mcrypt.php
+        require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
+    }
+    $RandomCompatUrandom = null;
+
+    /**
+     * This is a Windows-specific fallback, for when the mcrypt extension
+     * isn't loaded.
+     */
+    if (
+        !is_callable('random_bytes')
+        &&
+        extension_loaded('com_dotnet')
+        &&
+        class_exists('COM')
+    ) {
+        $RandomCompat_disabled_classes = preg_split(
+            '#\s*,\s*#',
+            strtolower(ini_get('disable_classes'))
+        );
+
+        if (!in_array('com', $RandomCompat_disabled_classes)) {
+            try {
+                $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
+                if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
+                    // See random_bytes_com_dotnet.php
+                    require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
+                }
+            } catch (com_exception $e) {
+                // Don't try to use it.
+            }
+        }
+        $RandomCompat_disabled_classes = null;
+        $RandomCompatCOMtest = null;
+    }
+
+    /**
+     * throw new Exception
+     */
+    if (!is_callable('random_bytes')) {
+        /**
+         * We don't have any more options, so let's throw an exception right now
+         * and hope the developer won't let it fail silently.
+         *
+         * @param mixed $length
+         * @psalm-suppress InvalidReturnType
+         * @throws Exception
+         * @return string
+         */
+        function random_bytes($length)
+        {
+            unset($length); // Suppress "variable not used" warnings.
+            throw new Exception(
+                'There is no suitable CSPRNG installed on your system'
+            );
+            return '';
+        }
+    }
+}
+
+if (!is_callable('random_int')) {
+    require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
+}
+
+$RandomCompatDIR = null;
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php
new file mode 100644 (file)
index 0000000..537d02b
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('random_bytes')) {
+    /**
+     * Windows with PHP < 5.3.0 will not have the function
+     * openssl_random_pseudo_bytes() available, so let's use
+     * CAPICOM to work around this deficiency.
+     *
+     * @param int $bytes
+     *
+     * @throws Exception
+     *
+     * @return string
+     */
+    function random_bytes($bytes)
+    {
+        try {
+            /** @var int $bytes */
+            $bytes = RandomCompat_intval($bytes);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_bytes(): $bytes must be an integer'
+            );
+        }
+
+        if ($bytes < 1) {
+            throw new Error(
+                'Length must be greater than 0'
+            );
+        }
+
+        /** @var string $buf */
+        $buf = '';
+        if (!class_exists('COM')) {
+            throw new Error(
+                'COM does not exist'
+            );
+        }
+        /** @var COM $util */
+        $util = new COM('CAPICOM.Utilities.1');
+        $execCount = 0;
+
+        /**
+         * Let's not let it loop forever. If we run N times and fail to
+         * get N bytes of random data, then CAPICOM has failed us.
+         */
+        do {
+            $buf .= base64_decode((string) $util->GetRandom($bytes, 0));
+            if (RandomCompat_strlen($buf) >= $bytes) {
+                /**
+                 * Return our random entropy buffer here:
+                 */
+                return (string) RandomCompat_substr($buf, 0, $bytes);
+            }
+            ++$execCount;
+        } while ($execCount < $bytes);
+
+        /**
+         * If we reach here, PHP has failed us.
+         */
+        throw new Exception(
+            'Could not gather sufficient random data'
+        );
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php
new file mode 100644 (file)
index 0000000..c4e31cc
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
+    define('RANDOM_COMPAT_READ_BUFFER', 8);
+}
+
+if (!is_callable('random_bytes')) {
+    /**
+     * Unless open_basedir is enabled, use /dev/urandom for
+     * random numbers in accordance with best practices
+     *
+     * Why we use /dev/urandom and not /dev/random
+     * @ref https://www.2uo.de/myths-about-urandom
+     * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
+     *
+     * @param int $bytes
+     *
+     * @throws Exception
+     *
+     * @return string
+     */
+    function random_bytes($bytes)
+    {
+        /** @var resource $fp */
+        static $fp = null;
+
+        /**
+         * This block should only be run once
+         */
+        if (empty($fp)) {
+            /**
+             * We don't want to ever read C:\dev\random, only /dev/urandom on
+             * Unix-like operating systems. While we guard against this
+             * condition in random.php, it doesn't hurt to be defensive in depth
+             * here.
+             *
+             * To that end, we only try to open /dev/urandom if we're on a Unix-
+             * like operating system (which means the directory separator is set
+             * to "/" not "\".
+             */
+            if (DIRECTORY_SEPARATOR === '/') {
+                if (!is_readable('/dev/urandom')) {
+                    throw new Exception(
+                        'Environment misconfiguration: ' .
+                        '/dev/urandom cannot be read.'
+                    );
+                }
+                /**
+                 * We use /dev/urandom if it is a char device.
+                 * We never fall back to /dev/random
+                 */
+                /** @var resource|bool $fp */
+                $fp = fopen('/dev/urandom', 'rb');
+                if (is_resource($fp)) {
+                    /** @var array<string, int> $st */
+                    $st = fstat($fp);
+                    if (($st['mode'] & 0170000) !== 020000) {
+                        fclose($fp);
+                        $fp = false;
+                    }
+                }
+            }
+
+            if (is_resource($fp)) {
+                /**
+                 * stream_set_read_buffer() does not exist in HHVM
+                 *
+                 * If we don't set the stream's read buffer to 0, PHP will
+                 * internally buffer 8192 bytes, which can waste entropy
+                 *
+                 * stream_set_read_buffer returns 0 on success
+                 */
+                if (is_callable('stream_set_read_buffer')) {
+                    stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
+                }
+                if (is_callable('stream_set_chunk_size')) {
+                    stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
+                }
+            }
+        }
+
+        try {
+            /** @var int $bytes */
+            $bytes = RandomCompat_intval($bytes);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_bytes(): $bytes must be an integer'
+            );
+        }
+
+        if ($bytes < 1) {
+            throw new Error(
+                'Length must be greater than 0'
+            );
+        }
+
+        /**
+         * This if() block only runs if we managed to open a file handle
+         *
+         * It does not belong in an else {} block, because the above
+         * if (empty($fp)) line is logic that should only be run once per
+         * page load.
+         */
+        if (is_resource($fp)) {
+            /**
+             * @var int
+             */
+            $remaining = $bytes;
+
+            /**
+             * @var string|bool
+             */
+            $buf = '';
+
+            /**
+             * We use fread() in a loop to protect against partial reads
+             */
+            do {
+                /**
+                 * @var string|bool
+                 */
+                $read = fread($fp, $remaining);
+                if (!is_string($read)) {
+                    /**
+                     * We cannot safely read from the file. Exit the
+                     * do-while loop and trigger the exception condition
+                     *
+                     * @var string|bool
+                     */
+                    $buf = false;
+                    break;
+                }
+                /**
+                 * Decrease the number of bytes returned from remaining
+                 */
+                $remaining -= RandomCompat_strlen($read);
+                /**
+                 * @var string $buf
+                 */
+                $buf .= $read;
+            } while ($remaining > 0);
+
+            /**
+             * Is our result valid?
+             * @var string|bool $buf
+             */
+            if (is_string($buf)) {
+                if (RandomCompat_strlen($buf) === $bytes) {
+                    /**
+                     * Return our random entropy buffer here:
+                     */
+                    return $buf;
+                }
+            }
+        }
+
+        /**
+         * If we reach here, PHP has failed us.
+         */
+        throw new Exception(
+            'Error reading from source device'
+        );
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php
new file mode 100644 (file)
index 0000000..2e56290
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('random_bytes')) {
+    /**
+     * If the libsodium PHP extension is loaded, we'll use it above any other
+     * solution.
+     *
+     * libsodium-php project:
+     * @ref https://github.com/jedisct1/libsodium-php
+     *
+     * @param int $bytes
+     *
+     * @throws Exception
+     *
+     * @return string
+     */
+    function random_bytes($bytes)
+    {
+        try {
+            /** @var int $bytes */
+            $bytes = RandomCompat_intval($bytes);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_bytes(): $bytes must be an integer'
+            );
+        }
+
+        if ($bytes < 1) {
+            throw new Error(
+                'Length must be greater than 0'
+            );
+        }
+
+        /**
+         * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
+         * generated in one invocation.
+         */
+        /** @var string|bool $buf */
+        if ($bytes > 2147483647) {
+            $buf = '';
+            for ($i = 0; $i < $bytes; $i += 1073741824) {
+                $n = ($bytes - $i) > 1073741824
+                    ? 1073741824
+                    : $bytes - $i;
+                $buf .= \Sodium\randombytes_buf($n);
+            }
+        } else {
+            /** @var string|bool $buf */
+            $buf = \Sodium\randombytes_buf($bytes);
+        }
+
+        if (is_string($buf)) {
+            if (RandomCompat_strlen($buf) === $bytes) {
+                return $buf;
+            }
+        }
+
+        /**
+         * If we reach here, PHP has failed us.
+         */
+        throw new Exception(
+            'Could not gather sufficient random data'
+        );
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php
new file mode 100644 (file)
index 0000000..f78b219
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('random_bytes')) {
+    /**
+     * If the libsodium PHP extension is loaded, we'll use it above any other
+     * solution.
+     *
+     * libsodium-php project:
+     * @ref https://github.com/jedisct1/libsodium-php
+     *
+     * @param int $bytes
+     *
+     * @throws Exception
+     *
+     * @return string
+     */
+    function random_bytes($bytes)
+    {
+        try {
+            /** @var int $bytes */
+            $bytes = RandomCompat_intval($bytes);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_bytes(): $bytes must be an integer'
+            );
+        }
+
+        if ($bytes < 1) {
+            throw new Error(
+                'Length must be greater than 0'
+            );
+        }
+
+        /**
+         * @var string
+         */
+        $buf = '';
+
+        /**
+         * \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
+         * generated in one invocation.
+         */
+        if ($bytes > 2147483647) {
+            for ($i = 0; $i < $bytes; $i += 1073741824) {
+                $n = ($bytes - $i) > 1073741824
+                    ? 1073741824
+                    : $bytes - $i;
+                $buf .= Sodium::randombytes_buf((int) $n);
+            }
+        } else {
+            $buf .= Sodium::randombytes_buf((int) $bytes);
+        }
+
+        if (is_string($buf)) {
+            if (RandomCompat_strlen($buf) === $bytes) {
+                return $buf;
+            }
+        }
+
+        /**
+         * If we reach here, PHP has failed us.
+         */
+        throw new Exception(
+            'Could not gather sufficient random data'
+        );
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php
new file mode 100644 (file)
index 0000000..0b13fa7
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+if (!is_callable('random_bytes')) {
+    /**
+     * Powered by ext/mcrypt (and thankfully NOT libmcrypt)
+     *
+     * @ref https://bugs.php.net/bug.php?id=55169
+     * @ref https://github.com/php/php-src/blob/c568ffe5171d942161fc8dda066bce844bdef676/ext/mcrypt/mcrypt.c#L1321-L1386
+     *
+     * @param int $bytes
+     *
+     * @throws Exception
+     *
+     * @return string
+     */
+    function random_bytes($bytes)
+    {
+        try {
+            /** @var int $bytes */
+            $bytes = RandomCompat_intval($bytes);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_bytes(): $bytes must be an integer'
+            );
+        }
+
+        if ($bytes < 1) {
+            throw new Error(
+                'Length must be greater than 0'
+            );
+        }
+
+        /** @var string|bool $buf */
+        $buf = @mcrypt_create_iv((int) $bytes, (int) MCRYPT_DEV_URANDOM);
+        if (
+            is_string($buf)
+                &&
+            RandomCompat_strlen($buf) === $bytes
+        ) {
+            /**
+             * Return our random entropy buffer here:
+             */
+            return $buf;
+        }
+
+        /**
+         * If we reach here, PHP has failed us.
+         */
+        throw new Exception(
+            'Could not gather sufficient random data'
+        );
+    }
+}
diff --git a/vendor/paragonie/random_compat/lib/random_int.php b/vendor/paragonie/random_compat/lib/random_int.php
new file mode 100644 (file)
index 0000000..ff80dfa
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+
+if (!is_callable('random_int')) {
+    /**
+     * Random_* Compatibility Library
+     * for using the new PHP 7 random_* API in PHP 5 projects
+     *
+     * The MIT License (MIT)
+     *
+     * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
+     *
+     * Permission is hereby granted, free of charge, to any person obtaining a copy
+     * of this software and associated documentation files (the "Software"), to deal
+     * in the Software without restriction, including without limitation the rights
+     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+     * copies of the Software, and to permit persons to whom the Software is
+     * furnished to do so, subject to the following conditions:
+     *
+     * The above copyright notice and this permission notice shall be included in
+     * all copies or substantial portions of the Software.
+     *
+     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+     * SOFTWARE.
+     */
+
+    /**
+     * Fetch a random integer between $min and $max inclusive
+     *
+     * @param int $min
+     * @param int $max
+     *
+     * @throws Exception
+     *
+     * @return int
+     */
+    function random_int($min, $max)
+    {
+        /**
+         * Type and input logic checks
+         *
+         * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
+         * (non-inclusive), it will sanely cast it to an int. If you it's equal to
+         * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
+         * lose precision, so the <= and => operators might accidentally let a float
+         * through.
+         */
+
+        try {
+            /** @var int $min */
+            $min = RandomCompat_intval($min);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_int(): $min must be an integer'
+            );
+        }
+
+        try {
+            /** @var int $max */
+            $max = RandomCompat_intval($max);
+        } catch (TypeError $ex) {
+            throw new TypeError(
+                'random_int(): $max must be an integer'
+            );
+        }
+
+        /**
+         * Now that we've verified our weak typing system has given us an integer,
+         * let's validate the logic then we can move forward with generating random
+         * integers along a given range.
+         */
+        if ($min > $max) {
+            throw new Error(
+                'Minimum value must be less than or equal to the maximum value'
+            );
+        }
+
+        if ($max === $min) {
+            return (int) $min;
+        }
+
+        /**
+         * Initialize variables to 0
+         *
+         * We want to store:
+         * $bytes => the number of random bytes we need
+         * $mask => an integer bitmask (for use with the &) operator
+         *          so we can minimize the number of discards
+         */
+        $attempts = $bits = $bytes = $mask = $valueShift = 0;
+        /** @var int $attempts */
+        /** @var int $bits */
+        /** @var int $bytes */
+        /** @var int $mask */
+        /** @var int $valueShift */
+
+        /**
+         * At this point, $range is a positive number greater than 0. It might
+         * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
+         * a float and we will lose some precision.
+         *
+         * @var int|float $range
+         */
+        $range = $max - $min;
+
+        /**
+         * Test for integer overflow:
+         */
+        if (!is_int($range)) {
+
+            /**
+             * Still safely calculate wider ranges.
+             * Provided by @CodesInChaos, @oittaa
+             *
+             * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435
+             *
+             * We use ~0 as a mask in this case because it generates all 1s
+             *
+             * @ref https://eval.in/400356 (32-bit)
+             * @ref http://3v4l.org/XX9r5  (64-bit)
+             */
+            $bytes = PHP_INT_SIZE;
+            /** @var int $mask */
+            $mask = ~0;
+
+        } else {
+
+            /**
+             * $bits is effectively ceil(log($range, 2)) without dealing with
+             * type juggling
+             */
+            while ($range > 0) {
+                if ($bits % 8 === 0) {
+                    ++$bytes;
+                }
+                ++$bits;
+                $range >>= 1;
+                /** @var int $mask */
+                $mask = $mask << 1 | 1;
+            }
+            $valueShift = $min;
+        }
+
+        /** @var int $val */
+        $val = 0;
+        /**
+         * Now that we have our parameters set up, let's begin generating
+         * random integers until one falls between $min and $max
+         */
+        /** @psalm-suppress RedundantCondition */
+        do {
+            /**
+             * The rejection probability is at most 0.5, so this corresponds
+             * to a failure probability of 2^-128 for a working RNG
+             */
+            if ($attempts > 128) {
+                throw new Exception(
+                    'random_int: RNG is broken - too many rejections'
+                );
+            }
+
+            /**
+             * Let's grab the necessary number of random bytes
+             */
+            $randomByteString = random_bytes($bytes);
+
+            /**
+             * Let's turn $randomByteString into an integer
+             *
+             * This uses bitwise operators (<< and |) to build an integer
+             * out of the values extracted from ord()
+             *
+             * Example: [9F] | [6D] | [32] | [0C] =>
+             *   159 + 27904 + 3276800 + 201326592 =>
+             *   204631455
+             */
+            $val &= 0;
+            for ($i = 0; $i < $bytes; ++$i) {
+                $val |= ord($randomByteString[$i]) << ($i * 8);
+            }
+            /** @var int $val */
+
+            /**
+             * Apply mask
+             */
+            $val &= $mask;
+            $val += $valueShift;
+
+            ++$attempts;
+            /**
+             * If $val overflows to a floating point number,
+             * ... or is larger than $max,
+             * ... or smaller than $min,
+             * then try again.
+             */
+        } while (!is_int($val) || $val > $max || $val < $min);
+
+        return (int) $val;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/composer.lock b/vendor/phpseclib/phpseclib/composer.lock
new file mode 100644 (file)
index 0000000..f50ebed
--- /dev/null
@@ -0,0 +1,1783 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "This file is @generated automatically"
+    ],
+    "hash": "422b05a6ce122760976256ff21e9381b",
+    "content-hash": "3bd75e9c1741d7c0c0930855e5b96abb",
+    "packages": [
+        {
+            "name": "paragonie/constant_time_encoding",
+            "version": "v1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/constant_time_encoding.git",
+                "reference": "fdb1e311153233315e0f7699711e3845d81ed00f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/fdb1e311153233315e0f7699711e3845d81ed00f",
+                "reference": "fdb1e311153233315e0f7699711e3845d81ed00f",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3|^7"
+            },
+            "require-dev": {
+                "paragonie/random_compat": "^1.4|^2.0",
+                "phpunit/phpunit": "4.*|5.*"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ParagonIE\\ConstantTime\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com",
+                    "role": "Maintainer"
+                },
+                {
+                    "name": "Steve 'Sc00bz' Thomas",
+                    "email": "steve@tobtu.com",
+                    "homepage": "https://www.tobtu.com",
+                    "role": "Original Developer"
+                }
+            ],
+            "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
+            "keywords": [
+                "base16",
+                "base32",
+                "base32_decode",
+                "base32_encode",
+                "base64",
+                "base64_decode",
+                "base64_encode",
+                "bin2hex",
+                "encoding",
+                "hex",
+                "hex2bin",
+                "rfc4648"
+            ],
+            "time": "2016-04-08 16:58:39"
+        },
+        {
+            "name": "paragonie/random_compat",
+            "version": "v2.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paragonie/random_compat.git",
+                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
+                "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*|5.*"
+            },
+            "suggest": {
+                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/random.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paragon Initiative Enterprises",
+                    "email": "security@paragonie.com",
+                    "homepage": "https://paragonie.com"
+                }
+            ],
+            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+            "keywords": [
+                "csprng",
+                "pseudorandom",
+                "random"
+            ],
+            "time": "2016-04-03 06:00:07"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "doctrine/instantiator",
+            "version": "1.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/instantiator.git",
+                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3,<8.0-DEV"
+            },
+            "require-dev": {
+                "athletic/athletic": "~0.1.8",
+                "ext-pdo": "*",
+                "ext-phar": "*",
+                "phpunit/phpunit": "~4.0",
+                "squizlabs/php_codesniffer": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com",
+                    "homepage": "http://ocramius.github.com/"
+                }
+            ],
+            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+            "homepage": "https://github.com/doctrine/instantiator",
+            "keywords": [
+                "constructor",
+                "instantiate"
+            ],
+            "time": "2015-06-14 21:17:01"
+        },
+        {
+            "name": "michelf/php-markdown",
+            "version": "1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/michelf/php-markdown.git",
+                "reference": "156e56ee036505ec637d761ee62dc425d807183c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/michelf/php-markdown/zipball/156e56ee036505ec637d761ee62dc425d807183c",
+                "reference": "156e56ee036505ec637d761ee62dc425d807183c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-lib": "1.4.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Michelf": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Michel Fortin",
+                    "email": "michel.fortin@michelf.ca",
+                    "homepage": "https://michelf.ca/",
+                    "role": "Developer"
+                },
+                {
+                    "name": "John Gruber",
+                    "homepage": "https://daringfireball.net/"
+                }
+            ],
+            "description": "PHP Markdown",
+            "homepage": "https://michelf.ca/projects/php-markdown/",
+            "keywords": [
+                "markdown"
+            ],
+            "time": "2015-12-24 01:37:31"
+        },
+        {
+            "name": "nikic/php-parser",
+            "version": "v0.9.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/PHP-Parser.git",
+                "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb",
+                "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": ">=5.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "PHPParser": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov"
+                }
+            ],
+            "description": "A PHP parser written in PHP",
+            "keywords": [
+                "parser",
+                "php"
+            ],
+            "time": "2014-07-23 18:24:17"
+        },
+        {
+            "name": "phing/phing",
+            "version": "2.14.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phingofficial/phing.git",
+                "reference": "7dd73c83c377623def54b58121f46b4dcb35dd61"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phingofficial/phing/zipball/7dd73c83c377623def54b58121f46b4dcb35dd61",
+                "reference": "7dd73c83c377623def54b58121f46b4dcb35dd61",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.0"
+            },
+            "require-dev": {
+                "ext-pdo_sqlite": "*",
+                "lastcraft/simpletest": "@dev",
+                "mikey179/vfsstream": "^1.6",
+                "pdepend/pdepend": "2.x",
+                "pear/archive_tar": "1.4.x",
+                "pear/http_request2": "dev-trunk",
+                "pear/net_growl": "dev-trunk",
+                "pear/pear-core-minimal": "1.10.1",
+                "pear/versioncontrol_git": "@dev",
+                "pear/versioncontrol_svn": "~0.5",
+                "phpdocumentor/phpdocumentor": "2.x",
+                "phploc/phploc": "~2.0.6",
+                "phpmd/phpmd": "~2.2",
+                "phpunit/phpunit": ">=3.7",
+                "sebastian/git": "~1.0",
+                "sebastian/phpcpd": "2.x",
+                "squizlabs/php_codesniffer": "~2.2",
+                "symfony/yaml": "~2.7"
+            },
+            "suggest": {
+                "pdepend/pdepend": "PHP version of JDepend",
+                "pear/archive_tar": "Tar file management class",
+                "pear/versioncontrol_git": "A library that provides OO interface to handle Git repository",
+                "pear/versioncontrol_svn": "A simple OO-style interface for Subversion, the free/open-source version control system",
+                "phpdocumentor/phpdocumentor": "Documentation Generator for PHP",
+                "phploc/phploc": "A tool for quickly measuring the size of a PHP project",
+                "phpmd/phpmd": "PHP version of PMD tool",
+                "phpunit/php-code-coverage": "Library that provides collection, processing, and rendering functionality for PHP code coverage information",
+                "phpunit/phpunit": "The PHP Unit Testing Framework",
+                "sebastian/phpcpd": "Copy/Paste Detector (CPD) for PHP code",
+                "tedivm/jshrink": "Javascript Minifier built in PHP"
+            },
+            "bin": [
+                "bin/phing"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.14.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "classes/phing/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "include-path": [
+                "classes"
+            ],
+            "license": [
+                "LGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Michiel Rook",
+                    "email": "mrook@php.net"
+                },
+                {
+                    "name": "Phing Community",
+                    "homepage": "https://www.phing.info/trac/wiki/Development/Contributors"
+                }
+            ],
+            "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.",
+            "homepage": "https://www.phing.info/",
+            "keywords": [
+                "build",
+                "phing",
+                "task",
+                "tool"
+            ],
+            "time": "2016-03-10 21:39:23"
+        },
+        {
+            "name": "phpdocumentor/reflection-docblock",
+            "version": "2.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
+                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "suggest": {
+                "dflydev/markdown": "~1.0",
+                "erusev/parsedown": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "phpDocumentor": [
+                        "src/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "mike.vanriel@naenius.com"
+                }
+            ],
+            "time": "2015-02-03 12:10:50"
+        },
+        {
+            "name": "phpspec/prophecy",
+            "version": "v1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpspec/prophecy.git",
+                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
+                "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.2",
+                "php": "^5.3|^7.0",
+                "phpdocumentor/reflection-docblock": "~2.0",
+                "sebastian/comparator": "~1.1",
+                "sebastian/recursion-context": "~1.0"
+            },
+            "require-dev": {
+                "phpspec/phpspec": "~2.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.5.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Prophecy\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Konstantin Kudryashov",
+                    "email": "ever.zet@gmail.com",
+                    "homepage": "http://everzet.com"
+                },
+                {
+                    "name": "Marcello Duarte",
+                    "email": "marcello.duarte@gmail.com"
+                }
+            ],
+            "description": "Highly opinionated mocking framework for PHP 5.3+",
+            "homepage": "https://github.com/phpspec/prophecy",
+            "keywords": [
+                "Double",
+                "Dummy",
+                "fake",
+                "mock",
+                "spy",
+                "stub"
+            ],
+            "time": "2016-02-15 07:46:21"
+        },
+        {
+            "name": "phpunit/php-code-coverage",
+            "version": "2.2.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "phpunit/php-file-iterator": "~1.3",
+                "phpunit/php-text-template": "~1.2",
+                "phpunit/php-token-stream": "~1.3",
+                "sebastian/environment": "^1.3.2",
+                "sebastian/version": "~1.0"
+            },
+            "require-dev": {
+                "ext-xdebug": ">=2.1.4",
+                "phpunit/phpunit": "~4"
+            },
+            "suggest": {
+                "ext-dom": "*",
+                "ext-xdebug": ">=2.2.1",
+                "ext-xmlwriter": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+            "keywords": [
+                "coverage",
+                "testing",
+                "xunit"
+            ],
+            "time": "2015-10-06 15:47:00"
+        },
+        {
+            "name": "phpunit/php-file-iterator",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+                "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+            "keywords": [
+                "filesystem",
+                "iterator"
+            ],
+            "time": "2015-06-21 13:08:43"
+        },
+        {
+            "name": "phpunit/php-text-template",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-text-template.git",
+                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Simple template engine.",
+            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+            "keywords": [
+                "template"
+            ],
+            "time": "2015-06-21 13:50:34"
+        },
+        {
+            "name": "phpunit/php-timer",
+            "version": "1.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-timer.git",
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
+                "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4|~5"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Utility class for timing",
+            "homepage": "https://github.com/sebastianbergmann/php-timer/",
+            "keywords": [
+                "timer"
+            ],
+            "time": "2016-05-12 18:03:57"
+        },
+        {
+            "name": "phpunit/php-token-stream",
+            "version": "1.4.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Wrapper around PHP's tokenizer extension.",
+            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+            "keywords": [
+                "tokenizer"
+            ],
+            "time": "2015-09-15 10:49:45"
+        },
+        {
+            "name": "phpunit/phpunit",
+            "version": "4.8.26",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit.git",
+                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
+                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-pcre": "*",
+                "ext-reflection": "*",
+                "ext-spl": "*",
+                "php": ">=5.3.3",
+                "phpspec/prophecy": "^1.3.1",
+                "phpunit/php-code-coverage": "~2.1",
+                "phpunit/php-file-iterator": "~1.4",
+                "phpunit/php-text-template": "~1.2",
+                "phpunit/php-timer": "^1.0.6",
+                "phpunit/phpunit-mock-objects": "~2.3",
+                "sebastian/comparator": "~1.1",
+                "sebastian/diff": "~1.2",
+                "sebastian/environment": "~1.3",
+                "sebastian/exporter": "~1.2",
+                "sebastian/global-state": "~1.0",
+                "sebastian/version": "~1.0",
+                "symfony/yaml": "~2.1|~3.0"
+            },
+            "suggest": {
+                "phpunit/php-invoker": "~1.1"
+            },
+            "bin": [
+                "phpunit"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.8.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "The PHP Unit Testing framework.",
+            "homepage": "https://phpunit.de/",
+            "keywords": [
+                "phpunit",
+                "testing",
+                "xunit"
+            ],
+            "time": "2016-05-17 03:09:28"
+        },
+        {
+            "name": "phpunit/phpunit-mock-objects",
+            "version": "2.3.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
+                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/instantiator": "^1.0.2",
+                "php": ">=5.3.3",
+                "phpunit/php-text-template": "~1.2",
+                "sebastian/exporter": "~1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "suggest": {
+                "ext-soap": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Mock Object library for PHPUnit",
+            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+            "keywords": [
+                "mock",
+                "xunit"
+            ],
+            "time": "2015-10-02 06:51:40"
+        },
+        {
+            "name": "pimple/pimple",
+            "version": "v2.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/silexphp/Pimple.git",
+                "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/silexphp/Pimple/zipball/ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
+                "reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Pimple": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
+            "homepage": "http://pimple.sensiolabs.org",
+            "keywords": [
+                "container",
+                "dependency injection"
+            ],
+            "time": "2014-07-24 07:10:08"
+        },
+        {
+            "name": "sami/sami",
+            "version": "v2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/FriendsOfPHP/Sami.git",
+                "reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/FriendsOfPHP/Sami/zipball/fa58b324f41aa2aefe21dac4f22d8c98965fc012",
+                "reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012",
+                "shasum": ""
+            },
+            "require": {
+                "michelf/php-markdown": "~1.3",
+                "nikic/php-parser": "0.9.*",
+                "php": ">=5.3.0",
+                "pimple/pimple": "2.*",
+                "symfony/console": "~2.1",
+                "symfony/filesystem": "~2.1",
+                "symfony/finder": "~2.1",
+                "symfony/process": "~2.1",
+                "symfony/yaml": "~2.1",
+                "twig/twig": "1.*"
+            },
+            "bin": [
+                "sami.php"
+            ],
+            "type": "application",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Sami": "."
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Sami, an API documentation generator",
+            "homepage": "http://sami.sensiolabs.org",
+            "keywords": [
+                "phpdoc"
+            ],
+            "time": "2014-06-25 12:05:18"
+        },
+        {
+            "name": "sebastian/comparator",
+            "version": "1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/comparator.git",
+                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
+                "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "sebastian/diff": "~1.2",
+                "sebastian/exporter": "~1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides the functionality to compare PHP values for equality",
+            "homepage": "http://www.github.com/sebastianbergmann/comparator",
+            "keywords": [
+                "comparator",
+                "compare",
+                "equality"
+            ],
+            "time": "2015-07-26 15:48:44"
+        },
+        {
+            "name": "sebastian/diff",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/diff.git",
+                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
+                "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Kore Nordmann",
+                    "email": "mail@kore-nordmann.de"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Diff implementation",
+            "homepage": "https://github.com/sebastianbergmann/diff",
+            "keywords": [
+                "diff"
+            ],
+            "time": "2015-12-08 07:14:41"
+        },
+        {
+            "name": "sebastian/environment",
+            "version": "1.3.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/environment.git",
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
+                "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides functionality to handle HHVM/PHP environments",
+            "homepage": "http://www.github.com/sebastianbergmann/environment",
+            "keywords": [
+                "Xdebug",
+                "environment",
+                "hhvm"
+            ],
+            "time": "2016-05-17 03:18:57"
+        },
+        {
+            "name": "sebastian/exporter",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/exporter.git",
+                "reference": "7ae5513327cb536431847bcc0c10edba2701064e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
+                "reference": "7ae5513327cb536431847bcc0c10edba2701064e",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "sebastian/recursion-context": "~1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Volker Dusch",
+                    "email": "github@wallbash.com"
+                },
+                {
+                    "name": "Bernhard Schussek",
+                    "email": "bschussek@2bepublished.at"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides the functionality to export PHP variables for visualization",
+            "homepage": "http://www.github.com/sebastianbergmann/exporter",
+            "keywords": [
+                "export",
+                "exporter"
+            ],
+            "time": "2015-06-21 07:55:53"
+        },
+        {
+            "name": "sebastian/global-state",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/global-state.git",
+                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
+                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.2"
+            },
+            "suggest": {
+                "ext-uopz": "*"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Snapshotting of global state",
+            "homepage": "http://www.github.com/sebastianbergmann/global-state",
+            "keywords": [
+                "global state"
+            ],
+            "time": "2015-10-12 03:26:01"
+        },
+        {
+            "name": "sebastian/recursion-context",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/recursion-context.git",
+                "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
+                "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.4"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Jeff Welch",
+                    "email": "whatthejeff@gmail.com"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "Adam Harvey",
+                    "email": "aharvey@php.net"
+                }
+            ],
+            "description": "Provides functionality to recursively process PHP variables",
+            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+            "time": "2015-11-11 19:50:13"
+        },
+        {
+            "name": "sebastian/version",
+            "version": "1.0.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
+                }
+            ],
+            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
+            "time": "2015-06-21 13:59:46"
+        },
+        {
+            "name": "squizlabs/php_codesniffer",
+            "version": "2.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
+                "reference": "1bcdf03b068a530ac1962ce671dead356eeba43b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1bcdf03b068a530ac1962ce671dead356eeba43b",
+                "reference": "1bcdf03b068a530ac1962ce671dead356eeba43b",
+                "shasum": ""
+            },
+            "require": {
+                "ext-simplexml": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": ">=5.1.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "bin": [
+                "scripts/phpcs",
+                "scripts/phpcbf"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "CodeSniffer.php",
+                    "CodeSniffer/CLI.php",
+                    "CodeSniffer/Exception.php",
+                    "CodeSniffer/File.php",
+                    "CodeSniffer/Fixer.php",
+                    "CodeSniffer/Report.php",
+                    "CodeSniffer/Reporting.php",
+                    "CodeSniffer/Sniff.php",
+                    "CodeSniffer/Tokens.php",
+                    "CodeSniffer/Reports/",
+                    "CodeSniffer/Tokenizers/",
+                    "CodeSniffer/DocGenerators/",
+                    "CodeSniffer/Standards/AbstractPatternSniff.php",
+                    "CodeSniffer/Standards/AbstractScopeSniff.php",
+                    "CodeSniffer/Standards/AbstractVariableSniff.php",
+                    "CodeSniffer/Standards/IncorrectPatternException.php",
+                    "CodeSniffer/Standards/Generic/Sniffs/",
+                    "CodeSniffer/Standards/MySource/Sniffs/",
+                    "CodeSniffer/Standards/PEAR/Sniffs/",
+                    "CodeSniffer/Standards/PSR1/Sniffs/",
+                    "CodeSniffer/Standards/PSR2/Sniffs/",
+                    "CodeSniffer/Standards/Squiz/Sniffs/",
+                    "CodeSniffer/Standards/Zend/Sniffs/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Greg Sherwood",
+                    "role": "lead"
+                }
+            ],
+            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
+            "homepage": "http://www.squizlabs.com/php-codesniffer",
+            "keywords": [
+                "phpcs",
+                "standards"
+            ],
+            "time": "2016-04-03 22:58:34"
+        },
+        {
+            "name": "symfony/console",
+            "version": "v2.8.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "48221d3de4dc22d2cd57c97e8b9361821da86609"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/48221d3de4dc22d2cd57c97e8b9361821da86609",
+                "reference": "48221d3de4dc22d2cd57c97e8b9361821da86609",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/event-dispatcher": "~2.1|~3.0.0",
+                "symfony/process": "~2.1|~3.0.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Console Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-26 12:00:47"
+        },
+        {
+            "name": "symfony/filesystem",
+            "version": "v2.8.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/filesystem.git",
+                "reference": "dee379131dceed90a429e951546b33edfe7dccbb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
+                "reference": "dee379131dceed90a429e951546b33edfe7dccbb",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Filesystem\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Filesystem Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-12 18:01:21"
+        },
+        {
+            "name": "symfony/finder",
+            "version": "v2.8.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/finder.git",
+                "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/ca24cf2cd4e3826f571e0067e535758e73807aa1",
+                "reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Finder\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Finder Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-10 10:53:53"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2016-05-18 14:26:46"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v2.8.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "1276bd9be89be039748cf753a2137f4ef149cd74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/1276bd9be89be039748cf753a2137f4ef149cd74",
+                "reference": "1276bd9be89be039748cf753a2137f4ef149cd74",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Process Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-04-14 15:22:22"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v2.8.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "e4fbcc65f90909c999ac3b4dfa699ee6563a9940"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/e4fbcc65f90909c999ac3b4dfa699ee6563a9940",
+                "reference": "e4fbcc65f90909c999ac3b4dfa699ee6563a9940",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-03-29 19:00:15"
+        },
+        {
+            "name": "twig/twig",
+            "version": "v1.24.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/twigphp/Twig.git",
+                "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
+                "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2.7"
+            },
+            "require-dev": {
+                "symfony/debug": "~2.7",
+                "symfony/phpunit-bridge": "~2.7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.24-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Twig_": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com",
+                    "homepage": "http://fabien.potencier.org",
+                    "role": "Lead Developer"
+                },
+                {
+                    "name": "Armin Ronacher",
+                    "email": "armin.ronacher@active-4.com",
+                    "role": "Project Founder"
+                },
+                {
+                    "name": "Twig Team",
+                    "homepage": "http://twig.sensiolabs.org/contributors",
+                    "role": "Contributors"
+                }
+            ],
+            "description": "Twig, the flexible, fast, and secure template language for PHP",
+            "homepage": "http://twig.sensiolabs.org",
+            "keywords": [
+                "templating"
+            ],
+            "time": "2016-01-25 21:22:18"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.3.3"
+    },
+    "platform-dev": []
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/MSBLOB.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/MSBLOB.php
new file mode 100644 (file)
index 0000000..b99dc2f
--- /dev/null
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Miccrosoft BLOB Formatted RSA Key Handler
+ *
+ * More info:
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx
+ *
+ * PHP version 5
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use phpseclib\Math\BigInteger;
+
+/**
+ * Microsoft BLOB Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class MSBLOB
+{
+    /**#@+
+     * @access private
+     */
+    /**
+     * Public/Private Key Pair
+     */
+    const PRIVATEKEYBLOB = 0x7;
+    /**
+     * Public Key
+     */
+    const PUBLICKEYBLOB = 0x6;
+    /**
+     * Public Key
+     */
+    const PUBLICKEYBLOBEX = 0xA;
+    /**
+     * RSA public key exchange algorithm
+     */
+    const CALG_RSA_KEYX = 0x0000A400;
+    /**
+     * RSA public key exchange algorithm
+     */
+    const CALG_RSA_SIGN = 0x00002400;
+    /**
+     * Public Key
+     */
+    const RSA1 = 0x31415352;
+    /**
+     * Private Key
+     */
+    const RSA2 = 0x32415352;
+    /**#@-*/
+
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_string($key)) {
+            return false;
+        }
+
+        $key = Base64::decode($key);
+
+        if (!is_string($key) || strlen($key) < 20) {
+            return false;
+        }
+
+        // PUBLICKEYSTRUC  publickeystruc
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
+        extract(unpack('atype/aversion/vreserved/Valgo', self::_string_shift($key, 8)));
+        switch (ord($type)) {
+            case self::PUBLICKEYBLOB:
+            case self::PUBLICKEYBLOBEX:
+                $publickey = true;
+                break;
+            case self::PRIVATEKEYBLOB:
+                $publickey = false;
+                break;
+            default:
+                return false;
+        }
+
+        $components = array('isPublicKey' => $publickey);
+
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
+        switch ($algo) {
+            case self::CALG_RSA_KEYX:
+            case self::CALG_RSA_SIGN:
+                break;
+            default:
+                return false;
+        }
+
+        // RSAPUBKEY rsapubkey
+        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
+        // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
+        extract(unpack('Vmagic/Vbitlen/a4pubexp', self::_string_shift($key, 12)));
+        switch ($magic) {
+            case self::RSA2:
+                $components['isPublicKey'] = false;
+            case self::RSA1:
+                break;
+            default:
+                return false;
+        }
+
+        $baseLength = $bitlen / 16;
+        if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
+            return false;
+        }
+
+        $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
+        // BYTE modulus[rsapubkey.bitlen/8]
+        $components['modulus'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
+
+        if ($publickey) {
+            return $components;
+        }
+
+        $components['isPublicKey'] = false;
+
+        // BYTE prime1[rsapubkey.bitlen/16]
+        $components['primes'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
+        // BYTE prime2[rsapubkey.bitlen/16]
+        $components['primes'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
+        // BYTE exponent1[rsapubkey.bitlen/16]
+        $components['exponents'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
+        // BYTE exponent2[rsapubkey.bitlen/16]
+        $components['exponents'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
+        // BYTE coefficient[rsapubkey.bitlen/16]
+        $components['coefficients'] = array(2 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
+        if (isset($components['privateExponent'])) {
+            $components['publicExponent'] = $components['privateExponent'];
+        }
+        // BYTE privateExponent[rsapubkey.bitlen/8]
+        $components['privateExponent'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
+
+        return $components;
+    }
+
+    /**
+     * Convert a private key to the appropriate format.
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @param \phpseclib\Math\BigInteger $d
+     * @param array $primes
+     * @param array $exponents
+     * @param array $coefficients
+     * @param string $password optional
+     * @return string
+     */
+    static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
+    {
+        $n = strrev($n->toBytes());
+        $e = str_pad(strrev($e->toBytes()), 4, "\0");
+        $key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
+        $key.= pack('VVa*', self::RSA2, 8 * strlen($n), $e);
+        $key.= $n;
+        $key.= strrev($primes[1]->toBytes());
+        $key.= strrev($primes[2]->toBytes());
+        $key.= strrev($exponents[1]->toBytes());
+        $key.= strrev($exponents[2]->toBytes());
+        $key.= strrev($coefficients[1]->toBytes());
+        $key.= strrev($d->toBytes());
+
+        return Base64::encode($key);
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        $n = strrev($n->toBytes());
+        $e = str_pad(strrev($e->toBytes()), 4, "\0");
+        $key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
+        $key.= pack('VVa*', self::RSA1, 8 * strlen($n), $e);
+        $key.= $n;
+
+        return Base64::encode($key);
+    }
+
+    /**
+     * String Shift
+     *
+     * Inspired by array_shift
+     *
+     * @param string $string
+     * @param int $index
+     * @return string
+     * @access private
+     */
+    static function _string_shift(&$string, $index = 1)
+    {
+        $substr = substr($string, 0, $index);
+        $string = substr($string, $index);
+        return $substr;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/OpenSSH.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/OpenSSH.php
new file mode 100644 (file)
index 0000000..8cd5328
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+/**
+ * OpenSSH Formatted RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * Place in $HOME/.ssh/authorized_keys
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use phpseclib\Math\BigInteger;
+
+/**
+ * OpenSSH Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class OpenSSH
+{
+    /**
+     * Default comment
+     *
+     * @var string
+     * @access private
+     */
+    static $comment = 'phpseclib-generated-key';
+
+    /**
+     * Sets the default comment
+     *
+     * @access public
+     * @param string $comment
+     */
+    static function setComment($comment)
+    {
+        self::$comment = str_replace(array("\r", "\n"), '', $comment);
+    }
+
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_string($key)) {
+            return false;
+        }
+
+        $parts = explode(' ', $key, 3);
+
+        $key = isset($parts[1]) ? Base64::decode($parts[1]) : Base64::decode($parts[0]);
+        if ($key === false) {
+            return false;
+        }
+
+        $comment = isset($parts[2]) ? $parts[2] : false;
+
+        if (substr($key, 0, 11) != "\0\0\0\7ssh-rsa") {
+            return false;
+        }
+        self::_string_shift($key, 11);
+        if (strlen($key) <= 4) {
+            return false;
+        }
+        extract(unpack('Nlength', self::_string_shift($key, 4)));
+        if (strlen($key) <= $length) {
+            return false;
+        }
+        $publicExponent = new BigInteger(self::_string_shift($key, $length), -256);
+        if (strlen($key) <= 4) {
+            return false;
+        }
+        extract(unpack('Nlength', self::_string_shift($key, 4)));
+        if (strlen($key) != $length) {
+            return false;
+        }
+        $modulus = new BigInteger(self::_string_shift($key, $length), -256);
+
+        return array(
+            'isPublicKey' => true,
+            'modulus' => $modulus,
+            'publicExponent' => $publicExponent,
+            'comment' => $comment
+        );
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        $publicExponent = $e->toBytes(true);
+        $modulus = $n->toBytes(true);
+
+        // from <http://tools.ietf.org/html/rfc4253#page-15>:
+        // string    "ssh-rsa"
+        // mpint     e
+        // mpint     n
+        $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
+        $RSAPublicKey = 'ssh-rsa ' . Base64::encode($RSAPublicKey) . ' ' . self::$comment;
+
+        return $RSAPublicKey;
+    }
+
+    /**
+     * String Shift
+     *
+     * Inspired by array_shift
+     *
+     * @param string $string
+     * @param int $index
+     * @return string
+     * @access private
+     */
+    static function _string_shift(&$string, $index = 1)
+    {
+        $substr = substr($string, 0, $index);
+        $string = substr($string, $index);
+        return $substr;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS.php
new file mode 100644 (file)
index 0000000..b0ff255
--- /dev/null
@@ -0,0 +1,487 @@
+<?php
+/**
+ * PKCS Formatted RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use ParagonIE\ConstantTime\Hex;
+use phpseclib\Crypt\AES;
+use phpseclib\Crypt\Base;
+use phpseclib\Crypt\DES;
+use phpseclib\Crypt\TripleDES;
+use phpseclib\Math\BigInteger;
+
+/**
+ * PKCS Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+abstract class PKCS
+{
+    /**#@+
+     * @access private
+     * @see \phpseclib\Crypt\RSA::createKey()
+     */
+    /**
+     * ASN1 Integer
+     */
+    const ASN1_INTEGER = 2;
+    /**
+     * ASN1 Bit String
+     */
+    const ASN1_BITSTRING = 3;
+    /**
+     * ASN1 Octet String
+     */
+    const ASN1_OCTETSTRING = 4;
+    /**
+     * ASN1 Object Identifier
+     */
+    const ASN1_OBJECT = 6;
+    /**
+     * ASN1 Sequence (with the constucted bit set)
+     */
+    const ASN1_SEQUENCE = 48;
+    /**#@-*/
+
+    /**#@+
+     * @access private
+     */
+    /**
+     * Auto-detect the format
+     */
+    const MODE_ANY = 0;
+    /**
+     * Require base64-encoded PEM's be supplied
+     */
+    const MODE_PEM = 1;
+    /**
+     * Require raw DER's be supplied
+     */
+    const MODE_DER = 2;
+    /**#@-*/
+
+    /**
+     * Is the key a base-64 encoded PEM, DER or should it be auto-detected?
+     *
+     * @access private
+     * @param int
+     */
+    static $format = self::MODE_ANY;
+
+    /**
+     * Returns the mode constant corresponding to the mode string
+     *
+     * @access public
+     * @param string $mode
+     * @return int
+     * @throws \UnexpectedValueException if the block cipher mode is unsupported
+     */
+    static function getEncryptionMode($mode)
+    {
+        switch ($mode) {
+            case 'CBC':
+                return Base::MODE_CBC;
+            case 'ECB':
+                return Base::MODE_ECB;
+            case 'CFB':
+                return Base::MODE_CFB;
+            case 'OFB':
+                return Base::MODE_OFB;
+            case 'CTR':
+                return Base::MODE_CTR;
+        }
+        throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
+    }
+
+    /**
+     * Returns a cipher object corresponding to a string
+     *
+     * @access public
+     * @param string $algo
+     * @return string
+     * @throws \UnexpectedValueException if the encryption algorithm is unsupported
+     */
+    static function getEncryptionObject($algo)
+    {
+        $modes = '(CBC|ECB|CFB|OFB|CTR)';
+        switch (true) {
+            case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
+                $cipher = new AES(self::getEncryptionMode($matches[2]));
+                $cipher->setKeyLength($matches[1]);
+                return $cipher;
+            case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
+                return new TripleDES(self::getEncryptionMode($matches[1]));
+            case preg_match("#^DES-$modes$#", $algo, $matches):
+                return new DES(self::getEncryptionMode($matches[1]));
+            default:
+                throw new \UnexpectedValueException('Unsupported encryption algorithmn');
+        }
+    }
+
+    /**
+     * Generate a symmetric key for PKCS#1 keys
+     *
+     * @access public
+     * @param string $password
+     * @param string $iv
+     * @param int $length
+     * @return string
+     */
+    static function generateSymmetricKey($password, $iv, $length)
+    {
+        $symkey = '';
+        $iv = substr($iv, 0, 8);
+        while (strlen($symkey) < $length) {
+            $symkey.= md5($symkey . $password . $iv, true);
+        }
+        return substr($symkey, 0, $length);
+    }
+
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_string($key)) {
+            return false;
+        }
+
+        $components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false);
+
+        /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
+           "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
+           protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
+           two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:
+
+           http://tools.ietf.org/html/rfc1421#section-4.6.1.1
+           http://tools.ietf.org/html/rfc1421#section-4.6.1.3
+
+           DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
+           DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
+           function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
+           own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
+           implementation are part of the standard, as well.
+
+           * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
+        if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
+            $iv = Hex::decode(trim($matches[2]));
+            // remove the Proc-Type / DEK-Info sections as they're no longer needed
+            $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
+            $ciphertext = self::_extractBER($key);
+            if ($ciphertext === false) {
+                $ciphertext = $key;
+            }
+            $crypto = self::getEncryptionObject($matches[1]);
+            $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
+            $crypto->setIV($iv);
+            $key = $crypto->decrypt($ciphertext);
+            if ($key === false) {
+                return false;
+            }
+        } else {
+            if (self::$format != self::MODE_DER) {
+                $decoded = self::_extractBER($key);
+                if ($decoded !== false) {
+                    $key = $decoded;
+                } elseif (self::$format == self::MODE_PEM) {
+                    return false;
+                }
+            }
+        }
+
+        if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
+            return false;
+        }
+        if (self::_decodeLength($key) != strlen($key)) {
+            return false;
+        }
+
+        $tag = ord(self::_string_shift($key));
+        /* intended for keys for which OpenSSL's asn1parse returns the following:
+
+            0:d=0  hl=4 l= 631 cons: SEQUENCE
+            4:d=1  hl=2 l=   1 prim:  INTEGER           :00
+            7:d=1  hl=2 l=  13 cons:  SEQUENCE
+            9:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
+           20:d=2  hl=2 l=   0 prim:   NULL
+           22:d=1  hl=4 l= 609 prim:  OCTET STRING
+
+           ie. PKCS8 keys */
+
+        if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
+            self::_string_shift($key, 3);
+            $tag = self::ASN1_SEQUENCE;
+        }
+
+        if ($tag == self::ASN1_SEQUENCE) {
+            $temp = self::_string_shift($key, self::_decodeLength($key));
+            if (ord(self::_string_shift($temp)) != self::ASN1_OBJECT) {
+                return false;
+            }
+            $length = self::_decodeLength($temp);
+            switch (self::_string_shift($temp, $length)) {
+                case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
+                    break;
+                case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
+                    /*
+                       PBEParameter ::= SEQUENCE {
+                           salt OCTET STRING (SIZE(8)),
+                           iterationCount INTEGER }
+                    */
+                    if (ord(self::_string_shift($temp)) != self::ASN1_SEQUENCE) {
+                        return false;
+                    }
+                    if (self::_decodeLength($temp) != strlen($temp)) {
+                        return false;
+                    }
+                    self::_string_shift($temp); // assume it's an octet string
+                    $salt = self::_string_shift($temp, self::_decodeLength($temp));
+                    if (ord(self::_string_shift($temp)) != self::ASN1_INTEGER) {
+                        return false;
+                    }
+                    self::_decodeLength($temp);
+                    list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
+                    self::_string_shift($key); // assume it's an octet string
+                    $length = self::_decodeLength($key);
+                    if (strlen($key) != $length) {
+                        return false;
+                    }
+
+                    $crypto = new DES(DES::MODE_CBC);
+                    $crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
+                    $key = $crypto->decrypt($key);
+                    if ($key === false) {
+                        return false;
+                    }
+                    return self::load($key);
+                default:
+                    return false;
+            }
+            /* intended for keys for which OpenSSL's asn1parse returns the following:
+
+                0:d=0  hl=4 l= 290 cons: SEQUENCE
+                4:d=1  hl=2 l=  13 cons:  SEQUENCE
+                6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
+               17:d=2  hl=2 l=   0 prim:   NULL
+               19:d=1  hl=4 l= 271 prim:  BIT STRING */
+            $tag = ord(self::_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
+            self::_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
+            // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
+            //  unused bits in the final subsequent octet. The number shall be in the range zero to seven."
+            //  -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
+            if ($tag == self::ASN1_BITSTRING) {
+                self::_string_shift($key);
+            }
+            if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
+                return false;
+            }
+            if (self::_decodeLength($key) != strlen($key)) {
+                return false;
+            }
+            $tag = ord(self::_string_shift($key));
+        }
+        if ($tag != self::ASN1_INTEGER) {
+            return false;
+        }
+
+        $length = self::_decodeLength($key);
+        $temp = self::_string_shift($key, $length);
+        if (strlen($temp) != 1 || ord($temp) > 2) {
+            $components['modulus'] = new BigInteger($temp, 256);
+            self::_string_shift($key); // skip over self::ASN1_INTEGER
+            $length = self::_decodeLength($key);
+            $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
+
+            return $components;
+        }
+        if (ord(self::_string_shift($key)) != self::ASN1_INTEGER) {
+            return false;
+        }
+        $length = self::_decodeLength($key);
+        $components['modulus'] = new BigInteger(self::_string_shift($key, $length), 256);
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['publicExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['primes'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['exponents'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
+        self::_string_shift($key);
+        $length = self::_decodeLength($key);
+        $components['coefficients'] = array(2 => new BigInteger(self::_string_shift($key, $length), 256));
+
+        if (!empty($key)) {
+            if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
+                return false;
+            }
+            self::_decodeLength($key);
+            while (!empty($key)) {
+                if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
+                    return false;
+                }
+                self::_decodeLength($key);
+                $key = substr($key, 1);
+                $length = self::_decodeLength($key);
+                $components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
+                self::_string_shift($key);
+                $length = self::_decodeLength($key);
+                $components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
+                self::_string_shift($key);
+                $length = self::_decodeLength($key);
+                $components['coefficients'][] = new BigInteger(self::_string_shift($key, $length), 256);
+            }
+        }
+
+        return $components;
+    }
+
+    /**
+     * Require base64-encoded PEM's be supplied
+     *
+     * @see self::load()
+     * @access public
+     */
+    static function requirePEM()
+    {
+        self::$format = self::MODE_PEM;
+    }
+
+    /**
+     * Require raw DER's be supplied
+     *
+     * @see self::load()
+     * @access public
+     */
+    static function requireDER()
+    {
+        self::$format = self::MODE_DER;
+    }
+
+    /**
+     * Accept any format and auto detect the format
+     *
+     * This is the default setting
+     *
+     * @see self::load()
+     * @access public
+     */
+    static function requireAny()
+    {
+        self::$format = self::MODE_ANY;
+    }
+
+    /**
+     * DER-decode the length
+     *
+     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
+     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
+     *
+     * @access private
+     * @param string $string
+     * @return int
+     */
+    static function _decodeLength(&$string)
+    {
+        $length = ord(self::_string_shift($string));
+        if ($length & 0x80) { // definite length, long form
+            $length&= 0x7F;
+            $temp = self::_string_shift($string, $length);
+            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
+        }
+        return $length;
+    }
+
+    /**
+     * DER-encode the length
+     *
+     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
+     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
+     *
+     * @access private
+     * @param int $length
+     * @return string
+     */
+    static function _encodeLength($length)
+    {
+        if ($length <= 0x7F) {
+            return chr($length);
+        }
+
+        $temp = ltrim(pack('N', $length), chr(0));
+        return pack('Ca*', 0x80 | strlen($temp), $temp);
+    }
+
+    /**
+     * String Shift
+     *
+     * Inspired by array_shift
+     *
+     * @param string $string
+     * @param int $index
+     * @return string
+     * @access private
+     */
+    static function _string_shift(&$string, $index = 1)
+    {
+        $substr = substr($string, 0, $index);
+        $string = substr($string, $index);
+        return $substr;
+    }
+
+    /**
+     * Extract raw BER from Base64 encoding
+     *
+     * @access private
+     * @param string $str
+     * @return string
+     */
+    static function _extractBER($str)
+    {
+        /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
+         * above and beyond the ceritificate.
+         * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
+         *
+         * Bag Attributes
+         *     localKeyID: 01 00 00 00
+         * subject=/O=organization/OU=org unit/CN=common name
+         * issuer=/O=organization/CN=common name
+         */
+        $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
+        // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
+        $temp = preg_replace('#-+[^-]+-+#', '', $temp);
+        // remove new lines
+        $temp = str_replace(array("\r", "\n", ' '), '', $temp);
+        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
+        return $temp != false ? $temp : $str;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS1.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS1.php
new file mode 100644 (file)
index 0000000..e5d6e1d
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+/**
+ * PKCS#1 Formatted RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * Used by File/X509.php
+ *
+ * Has the following header:
+ *
+ * -----BEGIN RSA PUBLIC KEY-----
+ *
+ * Analogous to ssh-keygen's pem format (as specified by -m)
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use ParagonIE\ConstantTime\Hex;
+use phpseclib\Crypt\AES;
+use phpseclib\Crypt\DES;
+use phpseclib\Crypt\Random;
+use phpseclib\Crypt\TripleDES;
+use phpseclib\Math\BigInteger;
+
+/**
+ * PKCS#1 Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class PKCS1 extends PKCS
+{
+    /**
+     * Default encryption algorithm
+     *
+     * @var string
+     * @access private
+     */
+    static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
+
+    /**
+     * Sets the default encryption algorithm
+     *
+     * @access public
+     * @param string $algo
+     */
+    static function setEncryptionAlgorithm($algo)
+    {
+        self::$defaultEncryptionAlgorithm = $algo;
+    }
+
+    /**
+     * Convert a private key to the appropriate format.
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @param \phpseclib\Math\BigInteger $d
+     * @param array $primes
+     * @param array $exponents
+     * @param array $coefficients
+     * @param string $password optional
+     * @return string
+     */
+    static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
+    {
+        $num_primes = count($primes);
+        $raw = array(
+            'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
+            'modulus' => $n->toBytes(true),
+            'publicExponent' => $e->toBytes(true),
+            'privateExponent' => $d->toBytes(true),
+            'prime1' => $primes[1]->toBytes(true),
+            'prime2' => $primes[2]->toBytes(true),
+            'exponent1' => $exponents[1]->toBytes(true),
+            'exponent2' => $exponents[2]->toBytes(true),
+            'coefficient' => $coefficients[2]->toBytes(true)
+        );
+
+        $components = array();
+        foreach ($raw as $name => $value) {
+            $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
+        }
+
+        $RSAPrivateKey = implode('', $components);
+
+        if ($num_primes > 2) {
+            $OtherPrimeInfos = '';
+            for ($i = 3; $i <= $num_primes; $i++) {
+                // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
+                //
+                // OtherPrimeInfo ::= SEQUENCE {
+                //     prime             INTEGER,  -- ri
+                //     exponent          INTEGER,  -- di
+                //     coefficient       INTEGER   -- ti
+                // }
+                $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
+                $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
+                $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
+                $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
+            }
+            $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
+        }
+
+        $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
+
+        if (!empty($password) || is_string($password)) {
+            $cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
+            $iv = Random::string($cipher->getBlockLength() >> 3);
+            $cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
+            $cipher->setIV($iv);
+            $iv = strtoupper(Hex::encode($iv));
+            $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
+                     "Proc-Type: 4,ENCRYPTED\r\n" .
+                     "DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
+                     "\r\n" .
+                     chunk_split(Base64::encode($cipher->encrypt($RSAPrivateKey)), 64) .
+                     '-----END RSA PRIVATE KEY-----';
+        } else {
+            $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
+                     chunk_split(Base64::encode($RSAPrivateKey), 64) .
+                     '-----END RSA PRIVATE KEY-----';
+        }
+
+        return $RSAPrivateKey;
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        $modulus = $n->toBytes(true);
+        $publicExponent = $e->toBytes(true);
+
+        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
+        // RSAPublicKey ::= SEQUENCE {
+        //     modulus           INTEGER,  -- n
+        //     publicExponent    INTEGER   -- e
+        // }
+        $components = array(
+            'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
+            'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
+        );
+
+        $RSAPublicKey = pack(
+            'Ca*a*a*',
+            self::ASN1_SEQUENCE,
+            self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
+            $components['modulus'],
+            $components['publicExponent']
+        );
+
+        $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
+                        chunk_split(Base64::encode($RSAPublicKey), 64) .
+                        '-----END RSA PUBLIC KEY-----';
+
+        return $RSAPublicKey;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS8.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PKCS8.php
new file mode 100644 (file)
index 0000000..787c89a
--- /dev/null
@@ -0,0 +1,209 @@
+<?php
+/**
+ * PKCS#8 Formatted RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
+ *
+ * Has the following header:
+ *
+ * -----BEGIN PUBLIC KEY-----
+ *
+ * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
+ * is specific to private keys it's basically creating a DER-encoded wrapper
+ * for keys. This just extends that same concept to public keys (much like ssh-keygen)
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use phpseclib\Crypt\DES;
+use phpseclib\Crypt\Random;
+use phpseclib\Math\BigInteger;
+
+/**
+ * PKCS#8 Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class PKCS8 extends PKCS
+{
+    /**
+     * Convert a private key to the appropriate format.
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @param \phpseclib\Math\BigInteger $d
+     * @param array $primes
+     * @param array $exponents
+     * @param array $coefficients
+     * @param string $password optional
+     * @return string
+     */
+    static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
+    {
+        $num_primes = count($primes);
+        $raw = array(
+            'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
+            'modulus' => $n->toBytes(true),
+            'publicExponent' => $e->toBytes(true),
+            'privateExponent' => $d->toBytes(true),
+            'prime1' => $primes[1]->toBytes(true),
+            'prime2' => $primes[2]->toBytes(true),
+            'exponent1' => $exponents[1]->toBytes(true),
+            'exponent2' => $exponents[2]->toBytes(true),
+            'coefficient' => $coefficients[2]->toBytes(true)
+        );
+
+        $components = array();
+        foreach ($raw as $name => $value) {
+            $components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
+        }
+
+        $RSAPrivateKey = implode('', $components);
+
+        if ($num_primes > 2) {
+            $OtherPrimeInfos = '';
+            for ($i = 3; $i <= $num_primes; $i++) {
+                // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
+                //
+                // OtherPrimeInfo ::= SEQUENCE {
+                //     prime             INTEGER,  -- ri
+                //     exponent          INTEGER,  -- di
+                //     coefficient       INTEGER   -- ti
+                // }
+                $OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
+                $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
+                $OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
+                $OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
+            }
+            $RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
+        }
+
+        $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
+
+        $rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
+        $RSAPrivateKey = pack(
+            'Ca*a*Ca*a*',
+            self::ASN1_INTEGER,
+            "\01\00",
+            $rsaOID,
+            4,
+            self::_encodeLength(strlen($RSAPrivateKey)),
+            $RSAPrivateKey
+        );
+        $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
+        if (!empty($password) || is_string($password)) {
+            $salt = Random::string(8);
+            $iterationCount = 2048;
+
+            $crypto = new DES(DES::MODE_CBC);
+            $crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
+            $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
+
+            $parameters = pack(
+                'Ca*a*Ca*N',
+                self::ASN1_OCTETSTRING,
+                self::_encodeLength(strlen($salt)),
+                $salt,
+                self::ASN1_INTEGER,
+                self::_encodeLength(4),
+                $iterationCount
+            );
+            $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
+
+            $encryptionAlgorithm = pack(
+                'Ca*a*Ca*a*',
+                self::ASN1_OBJECT,
+                self::_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
+                $pbeWithMD5AndDES_CBC,
+                self::ASN1_SEQUENCE,
+                self::_encodeLength(strlen($parameters)),
+                $parameters
+            );
+
+            $RSAPrivateKey = pack(
+                'Ca*a*Ca*a*',
+                self::ASN1_SEQUENCE,
+                self::_encodeLength(strlen($encryptionAlgorithm)),
+                $encryptionAlgorithm,
+                self::ASN1_OCTETSTRING,
+                self::_encodeLength(strlen($RSAPrivateKey)),
+                $RSAPrivateKey
+            );
+
+            $RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
+
+            $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
+                 chunk_split(Base64::encode($RSAPrivateKey), 64) .
+                 '-----END ENCRYPTED PRIVATE KEY-----';
+        } else {
+            $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
+                 chunk_split(Base64::encode($RSAPrivateKey), 64) .
+                 '-----END PRIVATE KEY-----';
+        }
+
+        return $RSAPrivateKey;
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        $modulus = $n->toBytes(true);
+        $publicExponent = $e->toBytes(true);
+
+        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
+        // RSAPublicKey ::= SEQUENCE {
+        //     modulus           INTEGER,  -- n
+        //     publicExponent    INTEGER   -- e
+        // }
+        $components = array(
+            'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
+            'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
+        );
+
+        $RSAPublicKey = pack(
+            'Ca*a*a*',
+            self::ASN1_SEQUENCE,
+            self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
+            $components['modulus'],
+            $components['publicExponent']
+        );
+
+        // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
+        $rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
+        $RSAPublicKey = chr(0) . $RSAPublicKey;
+        $RSAPublicKey = chr(3) . self::_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
+
+        $RSAPublicKey = pack(
+            'Ca*a*',
+            self::ASN1_SEQUENCE,
+            self::_encodeLength(strlen($rsaOID . $RSAPublicKey)),
+            $rsaOID . $RSAPublicKey
+        );
+
+        $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
+                        chunk_split(Base64::encode($RSAPublicKey), 64) .
+                        '-----END PUBLIC KEY-----';
+
+        return $RSAPublicKey;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PuTTY.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PuTTY.php
new file mode 100644 (file)
index 0000000..04c4ae2
--- /dev/null
@@ -0,0 +1,313 @@
+<?php
+/**
+ * PuTTY Formatted RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use ParagonIE\ConstantTime\Hex;
+use phpseclib\Crypt\AES;
+use phpseclib\Crypt\Hash;
+use phpseclib\Math\BigInteger;
+
+/**
+ * PuTTY Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class PuTTY
+{
+    /**
+     * Default comment
+     *
+     * @var string
+     * @access private
+     */
+    static $comment = 'phpseclib-generated-key';
+
+    /**
+     * Sets the default comment
+     *
+     * @access public
+     * @param string $comment
+     */
+    static function setComment($comment)
+    {
+        self::$comment = str_replace(array("\r", "\n"), '', $comment);
+    }
+
+    /**
+     * Generate a symmetric key for PuTTY keys
+     *
+     * @access public
+     * @param string $password
+     * @param string $iv
+     * @param int $length
+     * @return string
+     */
+    static function generateSymmetricKey($password, $length)
+    {
+        $symkey = '';
+        $sequence = 0;
+        while (strlen($symkey) < $length) {
+            $temp = pack('Na*', $sequence++, $password);
+            $symkey.= Hex::decode(sha1($temp));
+        }
+        return substr($symkey, 0, $length);
+    }
+
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_string($key)) {
+            return false;
+        }
+
+        static $one;
+        if (!isset($one)) {
+            $one = new BigInteger(1);
+        }
+
+        if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
+            $data = preg_split('#[\r\n]+#', $key);
+            $data = array_splice($data, 2, -1);
+            $data = implode('', $data);
+
+            $components = OpenSSH::load($data);
+            if ($components === false) {
+                return false;
+            }
+
+            if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
+                return false;
+            }
+            $components['comment'] = str_replace(array('\\\\', '\"'), array('\\', '"'), $matches[1]);
+
+            return $components;
+        }
+
+        $components = array('isPublicKey' => false);
+        $key = preg_split('#\r\n|\r|\n#', $key);
+        $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
+        if ($type != 'ssh-rsa') {
+            return false;
+        }
+        $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
+        $components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
+
+        $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
+        $public = Base64::decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
+        $public = substr($public, 11);
+        extract(unpack('Nlength', self::_string_shift($public, 4)));
+        $components['publicExponent'] = new BigInteger(self::_string_shift($public, $length), -256);
+        extract(unpack('Nlength', self::_string_shift($public, 4)));
+        $components['modulus'] = new BigInteger(self::_string_shift($public, $length), -256);
+
+        $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
+        $private = Base64::decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
+
+        switch ($encryption) {
+            case 'aes256-cbc':
+                $symkey = static::generateSymmetricKey($password, 32);
+                $crypto = new AES(AES::MODE_CBC);
+        }
+
+        if ($encryption != 'none') {
+            $crypto->setKey($symkey);
+            $crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
+            $crypto->disablePadding();
+            $private = $crypto->decrypt($private);
+            if ($private === false) {
+                return false;
+            }
+        }
+
+        extract(unpack('Nlength', self::_string_shift($private, 4)));
+        if (strlen($private) < $length) {
+            return false;
+        }
+        $components['privateExponent'] = new BigInteger(self::_string_shift($private, $length), -256);
+        extract(unpack('Nlength', self::_string_shift($private, 4)));
+        if (strlen($private) < $length) {
+            return false;
+        }
+        $components['primes'] = array(1 => new BigInteger(self::_string_shift($private, $length), -256));
+        extract(unpack('Nlength', self::_string_shift($private, 4)));
+        if (strlen($private) < $length) {
+            return false;
+        }
+        $components['primes'][] = new BigInteger(self::_string_shift($private, $length), -256);
+
+        $temp = $components['primes'][1]->subtract($one);
+        $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
+        $temp = $components['primes'][2]->subtract($one);
+        $components['exponents'][] = $components['publicExponent']->modInverse($temp);
+
+        extract(unpack('Nlength', self::_string_shift($private, 4)));
+        if (strlen($private) < $length) {
+            return false;
+        }
+        $components['coefficients'] = array(2 => new BigInteger(self::_string_shift($private, $length), -256));
+
+        return $components;
+    }
+
+    /**
+     * String Shift
+     *
+     * Inspired by array_shift
+     *
+     * @param string $string
+     * @param int $index
+     * @return string
+     * @access private
+     */
+    static function _string_shift(&$string, $index = 1)
+    {
+        $substr = substr($string, 0, $index);
+        $string = substr($string, $index);
+        return $substr;
+    }
+
+    /**
+     * Convert a private key to the appropriate format.
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @param \phpseclib\Math\BigInteger $d
+     * @param array $primes
+     * @param array $exponents
+     * @param array $coefficients
+     * @param string $password optional
+     * @return string
+     */
+    static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
+    {
+        if (count($primes) != 2) {
+            return false;
+        }
+
+        $raw = array(
+            'modulus' => $n->toBytes(true),
+            'publicExponent' => $e->toBytes(true),
+            'privateExponent' => $d->toBytes(true),
+            'prime1' => $primes[1]->toBytes(true),
+            'prime2' => $primes[2]->toBytes(true),
+            'exponent1' => $exponents[1]->toBytes(true),
+            'exponent2' => $exponents[2]->toBytes(true),
+            'coefficient' => $coefficients[2]->toBytes(true)
+        );
+
+        $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
+        $encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
+        $key.= $encryption;
+        $key.= "\r\nComment: " . self::$comment . "\r\n";
+        $public = pack(
+            'Na*Na*Na*',
+            strlen('ssh-rsa'),
+            'ssh-rsa',
+            strlen($raw['publicExponent']),
+            $raw['publicExponent'],
+            strlen($raw['modulus']),
+            $raw['modulus']
+        );
+        $source = pack(
+            'Na*Na*Na*Na*',
+            strlen('ssh-rsa'),
+            'ssh-rsa',
+            strlen($encryption),
+            $encryption,
+            strlen(self::$comment),
+            self::$comment,
+            strlen($public),
+            $public
+        );
+        $public = Base64::encode($public);
+        $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
+        $key.= chunk_split($public, 64);
+        $private = pack(
+            'Na*Na*Na*Na*',
+            strlen($raw['privateExponent']),
+            $raw['privateExponent'],
+            strlen($raw['prime1']),
+            $raw['prime1'],
+            strlen($raw['prime2']),
+            $raw['prime2'],
+            strlen($raw['coefficient']),
+            $raw['coefficient']
+        );
+        if (empty($password) && !is_string($password)) {
+            $source.= pack('Na*', strlen($private), $private);
+            $hashkey = 'putty-private-key-file-mac-key';
+        } else {
+            $private.= Random::string(16 - (strlen($private) & 15));
+            $source.= pack('Na*', strlen($private), $private);
+            $crypto = new AES();
+
+            $crypto->setKey(static::generateSymmetricKey($password, 32));
+            $crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
+            $crypto->disablePadding();
+            $private = $crypto->encrypt($private);
+            $hashkey = 'putty-private-key-file-mac-key' . $password;
+        }
+
+        $private = Base64::encode($private);
+        $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
+        $key.= chunk_split($private, 64);
+        $hash = new Hash('sha1');
+        $hash->setKey(sha1($hashkey, true));
+        $key.= 'Private-MAC: ' . Hex::encode($hash->hash($source)) . "\r\n";
+
+        return $key;
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        $n = $n->toBytes(true);
+        $e = $e->toBytes(true);
+
+        $key = pack(
+            'Na*Na*Na*',
+            strlen('ssh-rsa'),
+            'ssh-rsa',
+            strlen($e),
+            $e,
+            strlen($n),
+            $n
+        );
+        $key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
+               'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
+               chunk_split(Base64::encode($key), 64) .
+               '---- END SSH2 PUBLIC KEY ----';
+
+        return $key;
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Raw.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Raw.php
new file mode 100644 (file)
index 0000000..d399252
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Raw RSA Key Handler
+ *
+ * PHP version 5
+ *
+ * An array containing two \phpseclib\Math\BigInteger objects.
+ *
+ * The exponent can be indexed with any of the following:
+ *
+ * 0, e, exponent, publicExponent
+ *
+ * The modulus can be indexed with any of the following:
+ *
+ * 1, n, modulo, modulus
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use phpseclib\Math\BigInteger;
+
+/**
+ * Raw RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class Raw
+{
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_array($key)) {
+            return false;
+        }
+        if (isset($key['isPublicKey']) && isset($key['modulus'])) {
+            if (isset($key['privateExponent']) || isset($key['publicExponent'])) {
+                if (!isset($key['primes'])) {
+                    return $key;
+                }
+                if (isset($key['exponents']) && isset($key['coefficients']) && isset($key['publicExponent']) && isset($key['privateExponent'])) {
+                    return $key;
+                }
+            }
+        }
+        $components = array('isPublicKey' => true);
+        switch (true) {
+            case isset($key['e']):
+                $components['publicExponent'] = $key['e'];
+                break;
+            case isset($key['exponent']):
+                $components['publicExponent'] = $key['exponent'];
+                break;
+            case isset($key['publicExponent']):
+                $components['publicExponent'] = $key['publicExponent'];
+                break;
+            case isset($key[0]):
+                $components['publicExponent'] = $key[0];
+        }
+        switch (true) {
+            case isset($key['n']):
+                $components['modulus'] = $key['n'];
+                break;
+            case isset($key['modulo']):
+                $components['modulus'] = $key['modulo'];
+                break;
+            case isset($key['modulus']):
+                $components['modulus'] = $key['modulus'];
+                break;
+            case isset($key[1]):
+                $components['modulus'] = $key[1];
+        }
+        return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        return array('e' => clone $e, 'n' => clone $n);
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/XML.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/XML.php
new file mode 100644 (file)
index 0000000..a257033
--- /dev/null
@@ -0,0 +1,147 @@
+<?php
+/**
+ * XML Formatted RSA Key Handler
+ *
+ * More info:
+ *
+ * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
+ * http://en.wikipedia.org/wiki/XML_Signature
+ *
+ * PHP version 5
+ *
+ * @category  Crypt
+ * @package   RSA
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Crypt\RSA;
+
+use ParagonIE\ConstantTime\Base64;
+use phpseclib\Math\BigInteger;
+
+/**
+ * XML Formatted RSA Key Handler
+ *
+ * @package RSA
+ * @author  Jim Wigginton <terrafrost@php.net>
+ * @access  public
+ */
+class XML
+{
+    /**
+     * Break a public or private key down into its constituent components
+     *
+     * @access public
+     * @param string $key
+     * @param string $password optional
+     * @return array
+     */
+    static function load($key, $password = '')
+    {
+        if (!is_string($key)) {
+            return false;
+        }
+
+        $components = array(
+            'isPublicKey' => false,
+            'primes' => array(),
+            'exponents' => array(),
+            'coefficients' => array()
+        );
+
+        $use_errors = libxml_use_internal_errors(true);
+
+        $dom = new \DOMDocument();
+        if (!$dom->loadXML('<xml>' . $key . '</xml>')) {
+            return false;
+        }
+        $xpath = new \DOMXPath($dom);
+        $keys = array('modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd');
+        foreach ($keys as $key) {
+            // $dom->getElementsByTagName($key) is case-sensitive
+            $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
+            if (!$temp->length) {
+                continue;
+            }
+            $value = new BigInteger(Base64::decode($temp->item(0)->nodeValue), 256);
+            switch ($key) {
+                case 'modulus':
+                    $components['modulus'] = $value;
+                    break;
+                case 'exponent':
+                    $components['publicExponent'] = $value;
+                    break;
+                case 'p':
+                    $components['primes'][1] = $value;
+                    break;
+                case 'q':
+                    $components['primes'][2] = $value;
+                    break;
+                case 'dp':
+                    $components['exponents'][1] = $value;
+                    break;
+                case 'dq':
+                    $components['exponents'][2] = $value;
+                    break;
+                case 'inverseq':
+                    $components['coefficients'][2] = $value;
+                    break;
+                case 'd':
+                    $components['privateExponent'] = $value;
+            }
+        }
+
+        libxml_use_internal_errors($use_errors);
+
+        return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
+    }
+
+    /**
+     * Convert a private key to the appropriate format.
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @param \phpseclib\Math\BigInteger $d
+     * @param array $primes
+     * @param array $exponents
+     * @param array $coefficients
+     * @param string $password optional
+     * @return string
+     */
+    static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
+    {
+        if (count($primes) != 2) {
+            return false;
+        }
+        return "<RSAKeyValue>\r\n" .
+               '  <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
+               '  <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
+               '  <P>' . Base64::encode($primes[1]->toBytes()) . "</P>\r\n" .
+               '  <Q>' . Base64::encode($primes[2]->toBytes()) . "</Q>\r\n" .
+               '  <DP>' . Base64::encode($exponents[1]->toBytes()) . "</DP>\r\n" .
+               '  <DQ>' . Base64::encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
+               '  <InverseQ>' . Base64::encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
+               '  <D>' . Base64::encode($d->toBytes()) . "</D>\r\n" .
+               '</RSAKeyValue>';
+    }
+
+    /**
+     * Convert a public key to the appropriate format
+     *
+     * @access public
+     * @param \phpseclib\Math\BigInteger $n
+     * @param \phpseclib\Math\BigInteger $e
+     * @return string
+     */
+    static function savePublicKey(BigInteger $n, BigInteger $e)
+    {
+        return "<RSAKeyValue>\r\n" .
+               '  <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
+               '  <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
+               '</RSAKeyValue>';
+    }
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php b/vendor/phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php
new file mode 100644 (file)
index 0000000..096148a
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * BadConfigurationException
+ *
+ * PHP version 5
+ *
+ * @category  Exception
+ * @package   BadConfigurationException
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Exception;
+
+/**
+ * BadConfigurationException
+ *
+ * @package BadConfigurationException
+ * @author  Jim Wigginton <terrafrost@php.net>
+ */
+class BadConfigurationException extends \RuntimeException
+{
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Exception/FileNotFoundException.php b/vendor/phpseclib/phpseclib/phpseclib/Exception/FileNotFoundException.php
new file mode 100644 (file)
index 0000000..984edfc
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * FileNotFoundException
+ *
+ * PHP version 5
+ *
+ * @category  Exception
+ * @package   FileNotFoundException
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Exception;
+
+/**
+ * FileNotFoundException
+ *
+ * @package FileNotFoundException
+ * @author  Jim Wigginton <terrafrost@php.net>
+ */
+class FileNotFoundException extends \RuntimeException
+{
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Exception/NoSupportedAlgorithmsException.php b/vendor/phpseclib/phpseclib/phpseclib/Exception/NoSupportedAlgorithmsException.php
new file mode 100644 (file)
index 0000000..bca9a75
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * NoSupportedAlgorithmsException
+ *
+ * PHP version 5
+ *
+ * @category  Exception
+ * @package   NoSupportedAlgorithmsException
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Exception;
+
+/**
+ * NoSupportedAlgorithmsException
+ *
+ * @package NoSupportedAlgorithmsException
+ * @author  Jim Wigginton <terrafrost@php.net>
+ */
+class NoSupportedAlgorithmsException extends \RuntimeException
+{
+}
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.php b/vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.php
new file mode 100644 (file)
index 0000000..47cc41d
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * UnsupportedAlgorithmException
+ *
+ * PHP version 5
+ *
+ * @category  Exception
+ * @package   UnsupportedAlgorithmException
+ * @author    Jim Wigginton <terrafrost@php.net>
+ * @copyright 2015 Jim Wigginton
+ * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @link      http://phpseclib.sourceforge.net
+ */
+
+namespace phpseclib\Exception;
+
+/**
+ * UnsupportedAlgorithmException
+ *
+ * @package UnsupportedAlgorithmException
+ * @author  Jim Wigginton <terrafrost@php.net>
+ */
+class UnsupportedAlgorithmException extends \RuntimeException
+{
+}