summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:38:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:38:42 +0000
commitc3ca98e1b35123f226c7f4c596b5dee78caa4223 (patch)
tree9b6eb109283da55e7d9064baa9fac795a40264cb
parentInitial commit. (diff)
downloadicinga-php-thirdparty-c3ca98e1b35123f226c7f4c596b5dee78caa4223.tar.xz
icinga-php-thirdparty-c3ca98e1b35123f226c7f4c596b5dee78caa4223.zip
Adding upstream version 0.11.0.upstream/0.11.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.github/workflows/create-snapshot.yml39
-rw-r--r--.gitignore3
-rw-r--r--AssetLoader.php14
-rw-r--r--LICENSE21
-rw-r--r--README.md39
-rw-r--r--RELEASE.md11
-rw-r--r--VERSION1
-rw-r--r--asset/css/vendor/diff-table.less185
-rw-r--r--asset/js/jquery/jquery.js10881
-rw-r--r--asset/js/jquery/jquery.min.js2
-rwxr-xr-xbin/make-release.sh65
-rwxr-xr-xbin/make-snapshot.sh24
-rw-r--r--composer.json69
-rw-r--r--composer.lock3311
-rw-r--r--patches/ramsey-uuid.patch10
-rw-r--r--vendor/autoload.php12
-rw-r--r--vendor/clue/block-react/LICENSE21
-rw-r--r--vendor/clue/block-react/composer.json29
-rw-r--r--vendor/clue/block-react/src/functions.php357
-rw-r--r--vendor/clue/block-react/src/functions_include.php8
-rw-r--r--vendor/clue/buzz-react/LICENSE21
-rw-r--r--vendor/clue/buzz-react/composer.json38
-rw-r--r--vendor/clue/buzz-react/src/Browser.php867
-rw-r--r--vendor/clue/buzz-react/src/Io/ChunkedEncoder.php93
-rw-r--r--vendor/clue/buzz-react/src/Io/Sender.php161
-rw-r--r--vendor/clue/buzz-react/src/Io/Transaction.php305
-rw-r--r--vendor/clue/buzz-react/src/Message/MessageFactory.php139
-rw-r--r--vendor/clue/buzz-react/src/Message/ReadableBodyStream.php153
-rw-r--r--vendor/clue/buzz-react/src/Message/ResponseException.php43
-rw-r--r--vendor/clue/connection-manager-extra/LICENSE21
-rw-r--r--vendor/clue/connection-manager-extra/composer.json29
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php30
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php41
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php52
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php26
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php35
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php36
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php62
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php14
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php111
-rw-r--r--vendor/clue/http-proxy-react/LICENSE21
-rw-r--r--vendor/clue/http-proxy-react/composer.json31
-rw-r--r--vendor/clue/http-proxy-react/src/ProxyConnector.php274
-rw-r--r--vendor/clue/mq-react/LICENSE21
-rw-r--r--vendor/clue/mq-react/composer.json29
-rw-r--r--vendor/clue/mq-react/src/Queue.php448
-rw-r--r--vendor/clue/redis-protocol/composer.json19
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php51
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php31
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php23
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php100
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php53
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php40
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php10
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php28
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php125
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php151
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php111
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php83
-rw-r--r--vendor/clue/redis-react/LICENSE21
-rw-r--r--vendor/clue/redis-react/composer.json32
-rw-r--r--vendor/clue/redis-react/src/Client.php54
-rw-r--r--vendor/clue/redis-react/src/Factory.php191
-rw-r--r--vendor/clue/redis-react/src/LazyClient.php219
-rw-r--r--vendor/clue/redis-react/src/StreamingClient.php203
-rw-r--r--vendor/clue/soap-react/LICENSE21
-rw-r--r--vendor/clue/soap-react/composer.json27
-rw-r--r--vendor/clue/soap-react/src/Client.php323
-rw-r--r--vendor/clue/soap-react/src/Protocol/ClientDecoder.php53
-rw-r--r--vendor/clue/soap-react/src/Protocol/ClientEncoder.php69
-rw-r--r--vendor/clue/soap-react/src/Proxy.php50
-rw-r--r--vendor/clue/socket-raw/LICENSE21
-rw-r--r--vendor/clue/socket-raw/composer.json23
-rw-r--r--vendor/clue/socket-raw/src/Exception.php91
-rw-r--r--vendor/clue/socket-raw/src/Factory.php282
-rw-r--r--vendor/clue/socket-raw/src/Socket.php562
-rw-r--r--vendor/clue/socks-react/LICENSE21
-rw-r--r--vendor/clue/socks-react/composer.json31
-rw-r--r--vendor/clue/socks-react/src/Client.php452
-rw-r--r--vendor/clue/socks-react/src/Server.php399
-rw-r--r--vendor/clue/socks-react/src/StreamReader.php149
-rw-r--r--vendor/clue/stdio-react/LICENSE21
-rw-r--r--vendor/clue/stdio-react/composer.json37
-rw-r--r--vendor/clue/stdio-react/src/Readline.php1017
-rw-r--r--vendor/clue/stdio-react/src/Stdio.php630
-rw-r--r--vendor/clue/term-react/LICENSE21
-rw-r--r--vendor/clue/term-react/composer.json27
-rw-r--r--vendor/clue/term-react/src/ControlCodeParser.php223
-rw-r--r--vendor/clue/utf8-react/LICENSE21
-rw-r--r--vendor/clue/utf8-react/composer.json27
-rw-r--r--vendor/clue/utf8-react/src/Sequencer.php174
-rw-r--r--vendor/components/jquery/bower.json16
-rw-r--r--vendor/components/jquery/component.json22
-rw-r--r--vendor/components/jquery/composer.json34
-rw-r--r--vendor/components/jquery/package.json33
-rw-r--r--vendor/composer/ClassLoader.php572
-rw-r--r--vendor/composer/InstalledVersions.php352
-rw-r--r--vendor/composer/LICENSE21
-rw-r--r--vendor/composer/autoload_classmap.php11
-rw-r--r--vendor/composer/autoload_files.php24
-rw-r--r--vendor/composer/autoload_namespaces.php12
-rw-r--r--vendor/composer/autoload_psr4.php47
-rw-r--r--vendor/composer/autoload_real.php57
-rw-r--r--vendor/composer/autoload_static.php288
-rw-r--r--vendor/composer/installed.json3433
-rw-r--r--vendor/composer/installed.php449
-rw-r--r--vendor/composer/platform_check.php26
-rw-r--r--vendor/cweagans/composer-patches/composer.json30
-rw-r--r--vendor/cweagans/composer-patches/src/PatchEvent.php70
-rw-r--r--vendor/cweagans/composer-patches/src/PatchEvents.php30
-rw-r--r--vendor/cweagans/composer-patches/src/Patches.php594
-rw-r--r--vendor/evenement/evenement/LICENSE19
-rw-r--r--vendor/evenement/evenement/composer.json29
-rw-r--r--vendor/evenement/evenement/src/Evenement/EventEmitter.php17
-rw-r--r--vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php22
-rw-r--r--vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php135
-rw-r--r--vendor/fig/http-message-util/LICENSE19
-rw-r--r--vendor/fig/http-message-util/composer.json28
-rw-r--r--vendor/fig/http-message-util/src/RequestMethodInterface.php34
-rw-r--r--vendor/fig/http-message-util/src/StatusCodeInterface.php107
-rw-r--r--vendor/guzzlehttp/guzzle/LICENSE27
-rw-r--r--vendor/guzzlehttp/guzzle/composer.json89
-rw-r--r--vendor/guzzlehttp/guzzle/src/Client.php501
-rw-r--r--vendor/guzzlehttp/guzzle/src/ClientInterface.php87
-rw-r--r--vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php321
-rw-r--r--vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php84
-rw-r--r--vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php91
-rw-r--r--vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php72
-rw-r--r--vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php410
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php27
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/ClientException.php9
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php37
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php23
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php7
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/RequestException.php192
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/SeekException.php27
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/ServerException.php9
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php6
-rw-r--r--vendor/guzzlehttp/guzzle/src/Exception/TransferException.php6
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php585
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php27
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php45
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php219
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php92
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php195
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/Proxy.php55
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php545
-rw-r--r--vendor/guzzlehttp/guzzle/src/HandlerStack.php277
-rw-r--r--vendor/guzzlehttp/guzzle/src/MessageFormatter.php185
-rw-r--r--vendor/guzzlehttp/guzzle/src/Middleware.php254
-rw-r--r--vendor/guzzlehttp/guzzle/src/Pool.php134
-rw-r--r--vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php111
-rw-r--r--vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php281
-rw-r--r--vendor/guzzlehttp/guzzle/src/RequestOptions.php263
-rw-r--r--vendor/guzzlehttp/guzzle/src/RetryMiddleware.php128
-rw-r--r--vendor/guzzlehttp/guzzle/src/TransferStats.php126
-rw-r--r--vendor/guzzlehttp/guzzle/src/UriTemplate.php237
-rw-r--r--vendor/guzzlehttp/guzzle/src/Utils.php92
-rw-r--r--vendor/guzzlehttp/guzzle/src/functions.php334
-rw-r--r--vendor/guzzlehttp/guzzle/src/functions_include.php6
-rw-r--r--vendor/guzzlehttp/promises/LICENSE24
-rw-r--r--vendor/guzzlehttp/promises/composer.json58
-rw-r--r--vendor/guzzlehttp/promises/src/AggregateException.php17
-rw-r--r--vendor/guzzlehttp/promises/src/CancellationException.php10
-rw-r--r--vendor/guzzlehttp/promises/src/Coroutine.php169
-rw-r--r--vendor/guzzlehttp/promises/src/Create.php84
-rw-r--r--vendor/guzzlehttp/promises/src/Each.php90
-rw-r--r--vendor/guzzlehttp/promises/src/EachPromise.php255
-rw-r--r--vendor/guzzlehttp/promises/src/FulfilledPromise.php84
-rw-r--r--vendor/guzzlehttp/promises/src/Is.php46
-rw-r--r--vendor/guzzlehttp/promises/src/Promise.php278
-rw-r--r--vendor/guzzlehttp/promises/src/PromiseInterface.php97
-rw-r--r--vendor/guzzlehttp/promises/src/PromisorInterface.php16
-rw-r--r--vendor/guzzlehttp/promises/src/RejectedPromise.php91
-rw-r--r--vendor/guzzlehttp/promises/src/RejectionException.php48
-rw-r--r--vendor/guzzlehttp/promises/src/TaskQueue.php67
-rw-r--r--vendor/guzzlehttp/promises/src/TaskQueueInterface.php24
-rw-r--r--vendor/guzzlehttp/promises/src/Utils.php276
-rw-r--r--vendor/guzzlehttp/promises/src/functions.php363
-rw-r--r--vendor/guzzlehttp/promises/src/functions_include.php6
-rw-r--r--vendor/guzzlehttp/psr7/LICENSE26
-rw-r--r--vendor/guzzlehttp/psr7/composer.json76
-rw-r--r--vendor/guzzlehttp/psr7/src/AppendStream.php246
-rw-r--r--vendor/guzzlehttp/psr7/src/BufferStream.php142
-rw-r--r--vendor/guzzlehttp/psr7/src/CachingStream.php147
-rw-r--r--vendor/guzzlehttp/psr7/src/DroppingStream.php45
-rw-r--r--vendor/guzzlehttp/psr7/src/FnStream.php163
-rw-r--r--vendor/guzzlehttp/psr7/src/Header.php71
-rw-r--r--vendor/guzzlehttp/psr7/src/InflateStream.php56
-rw-r--r--vendor/guzzlehttp/psr7/src/LazyOpenStream.php42
-rw-r--r--vendor/guzzlehttp/psr7/src/LimitStream.php157
-rw-r--r--vendor/guzzlehttp/psr7/src/Message.php252
-rw-r--r--vendor/guzzlehttp/psr7/src/MessageTrait.php270
-rw-r--r--vendor/guzzlehttp/psr7/src/MimeType.php140
-rw-r--r--vendor/guzzlehttp/psr7/src/MultipartStream.php158
-rw-r--r--vendor/guzzlehttp/psr7/src/NoSeekStream.php25
-rw-r--r--vendor/guzzlehttp/psr7/src/PumpStream.php170
-rw-r--r--vendor/guzzlehttp/psr7/src/Query.php113
-rw-r--r--vendor/guzzlehttp/psr7/src/Request.php152
-rw-r--r--vendor/guzzlehttp/psr7/src/Response.php155
-rw-r--r--vendor/guzzlehttp/psr7/src/Rfc7230.php19
-rw-r--r--vendor/guzzlehttp/psr7/src/ServerRequest.php379
-rw-r--r--vendor/guzzlehttp/psr7/src/Stream.php270
-rw-r--r--vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php152
-rw-r--r--vendor/guzzlehttp/psr7/src/StreamWrapper.php165
-rw-r--r--vendor/guzzlehttp/psr7/src/UploadedFile.php328
-rw-r--r--vendor/guzzlehttp/psr7/src/Uri.php810
-rw-r--r--vendor/guzzlehttp/psr7/src/UriNormalizer.php219
-rw-r--r--vendor/guzzlehttp/psr7/src/UriResolver.php222
-rw-r--r--vendor/guzzlehttp/psr7/src/Utils.php428
-rw-r--r--vendor/guzzlehttp/psr7/src/functions.php422
-rw-r--r--vendor/guzzlehttp/psr7/src/functions_include.php6
-rw-r--r--vendor/jfcherng/php-color-output/LICENSE21
-rw-r--r--vendor/jfcherng/php-color-output/composer.json57
-rw-r--r--vendor/jfcherng/php-color-output/demo.php26
-rw-r--r--vendor/jfcherng/php-color-output/src/CliColor.php224
-rw-r--r--vendor/jfcherng/php-color-output/src/helpers.php37
-rw-r--r--vendor/jfcherng/php-diff/.php-cs-fixer.dist.php78
-rw-r--r--vendor/jfcherng/php-diff/.phpstorm.meta.php43
-rw-r--r--vendor/jfcherng/php-diff/LICENSE31
-rw-r--r--vendor/jfcherng/php-diff/composer.json69
-rw-r--r--vendor/jfcherng/php-diff/src/DiffHelper.php184
-rw-r--r--vendor/jfcherng/php-diff/src/Differ.php502
-rw-r--r--vendor/jfcherng/php-diff/src/Exception/FileNotFoundException.php13
-rw-r--r--vendor/jfcherng/php-diff/src/Exception/UnsupportedFunctionException.php13
-rw-r--r--vendor/jfcherng/php-diff/src/Factory/LineRendererFactory.php59
-rw-r--r--vendor/jfcherng/php-diff/src/Factory/RendererFactory.php83
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/AbstractRenderer.php230
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/AbstractHtml.php365
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/Combined.php505
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/Inline.php259
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/Json.php14
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/JsonHtml.php68
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/AbstractLineRenderer.php105
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Char.php36
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Line.php81
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/LineRendererInterface.php20
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/None.php20
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Word.php110
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Html/SideBySide.php274
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/RendererConstant.php116
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/RendererInterface.php35
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php145
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Text/Context.php163
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php81
-rw-r--r--vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php147
-rw-r--r--vendor/jfcherng/php-diff/src/Utility/Arr.php47
-rw-r--r--vendor/jfcherng/php-diff/src/Utility/Language.php137
-rw-r--r--vendor/jfcherng/php-diff/src/Utility/ReverseIterator.php51
-rw-r--r--vendor/jfcherng/php-diff/src/Utility/Str.php30
-rw-r--r--vendor/jfcherng/php-diff/src/languages/bul.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/chs.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/cht.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/deu.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/eng.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/fra.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/ita.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/jpn.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/por.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/rus.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/spa.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/tur.json5
-rw-r--r--vendor/jfcherng/php-diff/src/languages/ukr.json5
-rw-r--r--vendor/jfcherng/php-mb-string/LICENSE21
-rw-r--r--vendor/jfcherng/php-mb-string/composer.json50
-rw-r--r--vendor/jfcherng/php-mb-string/src/MbString.php367
-rw-r--r--vendor/jfcherng/php-sequence-matcher/.php-cs-fixer.dist.php78
-rw-r--r--vendor/jfcherng/php-sequence-matcher/LICENSE31
-rw-r--r--vendor/jfcherng/php-sequence-matcher/composer.json56
-rw-r--r--vendor/jfcherng/php-sequence-matcher/src/SequenceMatcher.php721
-rw-r--r--vendor/paragonie/random_compat/LICENSE22
-rw-r--r--vendor/paragonie/random_compat/composer.json34
-rw-r--r--vendor/paragonie/random_compat/lib/random.php32
-rw-r--r--vendor/paragonie/random_compat/other/build_phar.php57
-rw-r--r--vendor/paragonie/random_compat/psalm-autoload.php9
-rw-r--r--vendor/predis/predis/LICENSE22
-rw-r--r--vendor/predis/predis/autoload.php14
-rw-r--r--vendor/predis/predis/composer.json48
-rw-r--r--vendor/predis/predis/src/Autoloader.php62
-rw-r--r--vendor/predis/predis/src/Client.php550
-rw-r--r--vendor/predis/predis/src/ClientContextInterface.php199
-rw-r--r--vendor/predis/predis/src/ClientException.php21
-rw-r--r--vendor/predis/predis/src/ClientInterface.php240
-rw-r--r--vendor/predis/predis/src/Cluster/ClusterStrategy.php469
-rw-r--r--vendor/predis/predis/src/Cluster/Distributor/DistributorInterface.php82
-rw-r--r--vendor/predis/predis/src/Cluster/Distributor/EmptyRingException.php21
-rw-r--r--vendor/predis/predis/src/Cluster/Distributor/HashRing.php270
-rw-r--r--vendor/predis/predis/src/Cluster/Distributor/KetamaRing.php71
-rw-r--r--vendor/predis/predis/src/Cluster/Hash/CRC16.php74
-rw-r--r--vendor/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php30
-rw-r--r--vendor/predis/predis/src/Cluster/PredisStrategy.php79
-rw-r--r--vendor/predis/predis/src/Cluster/RedisStrategy.php58
-rw-r--r--vendor/predis/predis/src/Cluster/StrategyInterface.php53
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/CursorBasedIterator.php196
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/HashKey.php58
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/Keyspace.php43
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/ListKey.php181
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/SetKey.php47
-rw-r--r--vendor/predis/predis/src/Collection/Iterator/SortedSetKey.php58
-rw-r--r--vendor/predis/predis/src/Command/Command.php129
-rw-r--r--vendor/predis/predis/src/Command/CommandInterface.php81
-rw-r--r--vendor/predis/predis/src/Command/ConnectionAuth.php28
-rw-r--r--vendor/predis/predis/src/Command/ConnectionEcho.php28
-rw-r--r--vendor/predis/predis/src/Command/ConnectionPing.php28
-rw-r--r--vendor/predis/predis/src/Command/ConnectionQuit.php28
-rw-r--r--vendor/predis/predis/src/Command/ConnectionSelect.php28
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoAdd.php42
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoDist.php28
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoHash.php41
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoPos.php41
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoRadius.php71
-rw-r--r--vendor/predis/predis/src/Command/GeospatialGeoRadiusByMember.php28
-rw-r--r--vendor/predis/predis/src/Command/HashDelete.php36
-rw-r--r--vendor/predis/predis/src/Command/HashExists.php28
-rw-r--r--vendor/predis/predis/src/Command/HashGet.php28
-rw-r--r--vendor/predis/predis/src/Command/HashGetAll.php42
-rw-r--r--vendor/predis/predis/src/Command/HashGetMultiple.php36
-rw-r--r--vendor/predis/predis/src/Command/HashIncrementBy.php28
-rw-r--r--vendor/predis/predis/src/Command/HashIncrementByFloat.php28
-rw-r--r--vendor/predis/predis/src/Command/HashKeys.php28
-rw-r--r--vendor/predis/predis/src/Command/HashLength.php28
-rw-r--r--vendor/predis/predis/src/Command/HashScan.php85
-rw-r--r--vendor/predis/predis/src/Command/HashSet.php28
-rw-r--r--vendor/predis/predis/src/Command/HashSetMultiple.php48
-rw-r--r--vendor/predis/predis/src/Command/HashSetPreserve.php28
-rw-r--r--vendor/predis/predis/src/Command/HashStringLength.php28
-rw-r--r--vendor/predis/predis/src/Command/HashValues.php28
-rw-r--r--vendor/predis/predis/src/Command/HyperLogLogAdd.php36
-rw-r--r--vendor/predis/predis/src/Command/HyperLogLogCount.php36
-rw-r--r--vendor/predis/predis/src/Command/HyperLogLogMerge.php36
-rw-r--r--vendor/predis/predis/src/Command/KeyDelete.php36
-rw-r--r--vendor/predis/predis/src/Command/KeyDump.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyExists.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyExpire.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyExpireAt.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyKeys.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyMigrate.php50
-rw-r--r--vendor/predis/predis/src/Command/KeyMove.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyPersist.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyPreciseExpire.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyPreciseExpireAt.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyPreciseTimeToLive.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyRandom.php36
-rw-r--r--vendor/predis/predis/src/Command/KeyRename.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyRenamePreserve.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyRestore.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyScan.php66
-rw-r--r--vendor/predis/predis/src/Command/KeySort.php83
-rw-r--r--vendor/predis/predis/src/Command/KeyTimeToLive.php28
-rw-r--r--vendor/predis/predis/src/Command/KeyType.php28
-rw-r--r--vendor/predis/predis/src/Command/ListIndex.php28
-rw-r--r--vendor/predis/predis/src/Command/ListInsert.php28
-rw-r--r--vendor/predis/predis/src/Command/ListLength.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPopFirst.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPopFirstBlocking.php41
-rw-r--r--vendor/predis/predis/src/Command/ListPopLast.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPopLastBlocking.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPopLastPushHead.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPopLastPushHeadBlocking.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPushHead.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPushHeadX.php28
-rw-r--r--vendor/predis/predis/src/Command/ListPushTail.php36
-rw-r--r--vendor/predis/predis/src/Command/ListPushTailX.php28
-rw-r--r--vendor/predis/predis/src/Command/ListRange.php28
-rw-r--r--vendor/predis/predis/src/Command/ListRemove.php28
-rw-r--r--vendor/predis/predis/src/Command/ListSet.php28
-rw-r--r--vendor/predis/predis/src/Command/ListTrim.php28
-rw-r--r--vendor/predis/predis/src/Command/PrefixableCommandInterface.php27
-rw-r--r--vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php450
-rw-r--r--vendor/predis/predis/src/Command/Processor/ProcessorChain.php134
-rw-r--r--vendor/predis/predis/src/Command/Processor/ProcessorInterface.php29
-rw-r--r--vendor/predis/predis/src/Command/PubSubPublish.php28
-rw-r--r--vendor/predis/predis/src/Command/PubSubPubsub.php61
-rw-r--r--vendor/predis/predis/src/Command/PubSubSubscribe.php36
-rw-r--r--vendor/predis/predis/src/Command/PubSubSubscribeByPattern.php28
-rw-r--r--vendor/predis/predis/src/Command/PubSubUnsubscribe.php36
-rw-r--r--vendor/predis/predis/src/Command/PubSubUnsubscribeByPattern.php28
-rw-r--r--vendor/predis/predis/src/Command/RawCommand.php131
-rw-r--r--vendor/predis/predis/src/Command/ScriptCommand.php77
-rw-r--r--vendor/predis/predis/src/Command/ServerBackgroundRewriteAOF.php36
-rw-r--r--vendor/predis/predis/src/Command/ServerBackgroundSave.php36
-rw-r--r--vendor/predis/predis/src/Command/ServerClient.php74
-rw-r--r--vendor/predis/predis/src/Command/ServerCommand.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerConfig.php49
-rw-r--r--vendor/predis/predis/src/Command/ServerDatabaseSize.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerEval.php38
-rw-r--r--vendor/predis/predis/src/Command/ServerEvalSHA.php38
-rw-r--r--vendor/predis/predis/src/Command/ServerFlushAll.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerFlushDatabase.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerInfo.php111
-rw-r--r--vendor/predis/predis/src/Command/ServerInfoV26x.php56
-rw-r--r--vendor/predis/predis/src/Command/ServerLastSave.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerMonitor.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerObject.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerSave.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerScript.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerSentinel.php69
-rw-r--r--vendor/predis/predis/src/Command/ServerShutdown.php28
-rw-r--r--vendor/predis/predis/src/Command/ServerSlaveOf.php40
-rw-r--r--vendor/predis/predis/src/Command/ServerSlowlog.php51
-rw-r--r--vendor/predis/predis/src/Command/ServerTime.php28
-rw-r--r--vendor/predis/predis/src/Command/SetAdd.php36
-rw-r--r--vendor/predis/predis/src/Command/SetCardinality.php28
-rw-r--r--vendor/predis/predis/src/Command/SetDifference.php28
-rw-r--r--vendor/predis/predis/src/Command/SetDifferenceStore.php28
-rw-r--r--vendor/predis/predis/src/Command/SetIntersection.php36
-rw-r--r--vendor/predis/predis/src/Command/SetIntersectionStore.php40
-rw-r--r--vendor/predis/predis/src/Command/SetIsMember.php28
-rw-r--r--vendor/predis/predis/src/Command/SetMembers.php28
-rw-r--r--vendor/predis/predis/src/Command/SetMove.php28
-rw-r--r--vendor/predis/predis/src/Command/SetPop.php28
-rw-r--r--vendor/predis/predis/src/Command/SetRandomMember.php28
-rw-r--r--vendor/predis/predis/src/Command/SetRemove.php36
-rw-r--r--vendor/predis/predis/src/Command/SetScan.php66
-rw-r--r--vendor/predis/predis/src/Command/SetUnion.php28
-rw-r--r--vendor/predis/predis/src/Command/SetUnionStore.php28
-rw-r--r--vendor/predis/predis/src/Command/StringAppend.php28
-rw-r--r--vendor/predis/predis/src/Command/StringBitCount.php28
-rw-r--r--vendor/predis/predis/src/Command/StringBitField.php28
-rw-r--r--vendor/predis/predis/src/Command/StringBitOp.php42
-rw-r--r--vendor/predis/predis/src/Command/StringBitPos.php28
-rw-r--r--vendor/predis/predis/src/Command/StringDecrement.php28
-rw-r--r--vendor/predis/predis/src/Command/StringDecrementBy.php28
-rw-r--r--vendor/predis/predis/src/Command/StringGet.php28
-rw-r--r--vendor/predis/predis/src/Command/StringGetBit.php28
-rw-r--r--vendor/predis/predis/src/Command/StringGetMultiple.php36
-rw-r--r--vendor/predis/predis/src/Command/StringGetRange.php28
-rw-r--r--vendor/predis/predis/src/Command/StringGetSet.php28
-rw-r--r--vendor/predis/predis/src/Command/StringIncrement.php28
-rw-r--r--vendor/predis/predis/src/Command/StringIncrementBy.php28
-rw-r--r--vendor/predis/predis/src/Command/StringIncrementByFloat.php28
-rw-r--r--vendor/predis/predis/src/Command/StringPreciseSetExpire.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSet.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSetBit.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSetExpire.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSetMultiple.php48
-rw-r--r--vendor/predis/predis/src/Command/StringSetMultiplePreserve.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSetPreserve.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSetRange.php28
-rw-r--r--vendor/predis/predis/src/Command/StringStrlen.php28
-rw-r--r--vendor/predis/predis/src/Command/StringSubstr.php28
-rw-r--r--vendor/predis/predis/src/Command/TransactionDiscard.php28
-rw-r--r--vendor/predis/predis/src/Command/TransactionExec.php28
-rw-r--r--vendor/predis/predis/src/Command/TransactionMulti.php28
-rw-r--r--vendor/predis/predis/src/Command/TransactionUnwatch.php28
-rw-r--r--vendor/predis/predis/src/Command/TransactionWatch.php40
-rw-r--r--vendor/predis/predis/src/Command/ZSetAdd.php43
-rw-r--r--vendor/predis/predis/src/Command/ZSetCardinality.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetCount.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetIncrementBy.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetIntersectionStore.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetLexCount.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetRange.php105
-rw-r--r--vendor/predis/predis/src/Command/ZSetRangeByLex.php55
-rw-r--r--vendor/predis/predis/src/Command/ZSetRangeByScore.php68
-rw-r--r--vendor/predis/predis/src/Command/ZSetRank.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetRemove.php36
-rw-r--r--vendor/predis/predis/src/Command/ZSetRemoveRangeByLex.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetRemoveRangeByRank.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetRemoveRangeByScore.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetReverseRange.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetReverseRangeByLex.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetReverseRangeByScore.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetReverseRank.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetScan.php85
-rw-r--r--vendor/predis/predis/src/Command/ZSetScore.php28
-rw-r--r--vendor/predis/predis/src/Command/ZSetUnionStore.php78
-rw-r--r--vendor/predis/predis/src/CommunicationException.php85
-rw-r--r--vendor/predis/predis/src/Configuration/ClusterOption.php76
-rw-r--r--vendor/predis/predis/src/Configuration/ConnectionFactoryOption.php60
-rw-r--r--vendor/predis/predis/src/Configuration/ExceptionsOption.php37
-rw-r--r--vendor/predis/predis/src/Configuration/OptionInterface.php40
-rw-r--r--vendor/predis/predis/src/Configuration/Options.php122
-rw-r--r--vendor/predis/predis/src/Configuration/OptionsInterface.php70
-rw-r--r--vendor/predis/predis/src/Configuration/PrefixOption.php44
-rw-r--r--vendor/predis/predis/src/Configuration/ProfileOption.php69
-rw-r--r--vendor/predis/predis/src/Configuration/ReplicationOption.php77
-rw-r--r--vendor/predis/predis/src/Connection/AbstractConnection.php226
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/ClusterInterface.php24
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php509
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/PredisCluster.php237
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php675
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php52
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.php732
-rw-r--r--vendor/predis/predis/src/Connection/AggregateConnectionInterface.php57
-rw-r--r--vendor/predis/predis/src/Connection/CompositeConnectionInterface.php49
-rw-r--r--vendor/predis/predis/src/Connection/CompositeStreamConnection.php125
-rw-r--r--vendor/predis/predis/src/Connection/ConnectionException.php23
-rw-r--r--vendor/predis/predis/src/Connection/ConnectionInterface.php66
-rw-r--r--vendor/predis/predis/src/Connection/Factory.php192
-rw-r--r--vendor/predis/predis/src/Connection/FactoryInterface.php52
-rw-r--r--vendor/predis/predis/src/Connection/NodeConnectionInterface.php58
-rw-r--r--vendor/predis/predis/src/Connection/Parameters.php185
-rw-r--r--vendor/predis/predis/src/Connection/ParametersInterface.php62
-rw-r--r--vendor/predis/predis/src/Connection/PhpiredisSocketConnection.php418
-rw-r--r--vendor/predis/predis/src/Connection/PhpiredisStreamConnection.php262
-rw-r--r--vendor/predis/predis/src/Connection/StreamConnection.php396
-rw-r--r--vendor/predis/predis/src/Connection/WebdisConnection.php366
-rw-r--r--vendor/predis/predis/src/Monitor/Consumer.php178
-rw-r--r--vendor/predis/predis/src/NotSupportedException.php22
-rw-r--r--vendor/predis/predis/src/Pipeline/Atomic.php119
-rw-r--r--vendor/predis/predis/src/Pipeline/ConnectionErrorProof.php130
-rw-r--r--vendor/predis/predis/src/Pipeline/FireAndForget.php36
-rw-r--r--vendor/predis/predis/src/Pipeline/Pipeline.php247
-rw-r--r--vendor/predis/predis/src/PredisException.php21
-rw-r--r--vendor/predis/predis/src/Profile/Factory.php101
-rw-r--r--vendor/predis/predis/src/Profile/ProfileInterface.php59
-rw-r--r--vendor/predis/predis/src/Profile/RedisProfile.php146
-rw-r--r--vendor/predis/predis/src/Profile/RedisUnstable.php38
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion200.php173
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion220.php202
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion240.php207
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion260.php235
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion280.php267
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion300.php270
-rw-r--r--vendor/predis/predis/src/Profile/RedisVersion320.php281
-rw-r--r--vendor/predis/predis/src/Protocol/ProtocolException.php24
-rw-r--r--vendor/predis/predis/src/Protocol/ProtocolProcessorInterface.php41
-rw-r--r--vendor/predis/predis/src/Protocol/RequestSerializerInterface.php31
-rw-r--r--vendor/predis/predis/src/Protocol/ResponseReaderInterface.php32
-rw-r--r--vendor/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php107
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/BulkResponse.php55
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php34
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php46
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php68
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php33
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/StatusResponse.php35
-rw-r--r--vendor/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php47
-rw-r--r--vendor/predis/predis/src/Protocol/Text/ProtocolProcessor.php123
-rw-r--r--vendor/predis/predis/src/Protocol/Text/RequestSerializer.php46
-rw-r--r--vendor/predis/predis/src/Protocol/Text/ResponseReader.php116
-rw-r--r--vendor/predis/predis/src/PubSub/AbstractConsumer.php224
-rw-r--r--vendor/predis/predis/src/PubSub/Consumer.php158
-rw-r--r--vendor/predis/predis/src/PubSub/DispatcherLoop.php170
-rw-r--r--vendor/predis/predis/src/Replication/MissingMasterException.php23
-rw-r--r--vendor/predis/predis/src/Replication/ReplicationStrategy.php279
-rw-r--r--vendor/predis/predis/src/Replication/RoleException.php24
-rw-r--r--vendor/predis/predis/src/Response/Error.php59
-rw-r--r--vendor/predis/predis/src/Response/ErrorInterface.php35
-rw-r--r--vendor/predis/predis/src/Response/Iterator/MultiBulk.php77
-rw-r--r--vendor/predis/predis/src/Response/Iterator/MultiBulkIterator.php110
-rw-r--r--vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php91
-rw-r--r--vendor/predis/predis/src/Response/ResponseInterface.php21
-rw-r--r--vendor/predis/predis/src/Response/ServerException.php44
-rw-r--r--vendor/predis/predis/src/Response/Status.php79
-rw-r--r--vendor/predis/predis/src/Session/Handler.php148
-rw-r--r--vendor/predis/predis/src/Transaction/AbortedMultiExecException.php45
-rw-r--r--vendor/predis/predis/src/Transaction/MultiExec.php461
-rw-r--r--vendor/predis/predis/src/Transaction/MultiExecState.php166
-rw-r--r--vendor/psr/http-message/LICENSE19
-rw-r--r--vendor/psr/http-message/composer.json26
-rw-r--r--vendor/psr/http-message/src/MessageInterface.php187
-rw-r--r--vendor/psr/http-message/src/RequestInterface.php129
-rw-r--r--vendor/psr/http-message/src/ResponseInterface.php68
-rw-r--r--vendor/psr/http-message/src/ServerRequestInterface.php261
-rw-r--r--vendor/psr/http-message/src/StreamInterface.php158
-rw-r--r--vendor/psr/http-message/src/UploadedFileInterface.php123
-rw-r--r--vendor/psr/http-message/src/UriInterface.php323
-rw-r--r--vendor/ralouphie/getallheaders/LICENSE21
-rw-r--r--vendor/ralouphie/getallheaders/composer.json26
-rw-r--r--vendor/ralouphie/getallheaders/src/getallheaders.php46
-rw-r--r--vendor/ramsey/uuid/LICENSE21
-rw-r--r--vendor/ramsey/uuid/composer.json94
-rw-r--r--vendor/ramsey/uuid/src/BinaryUtils.php41
-rw-r--r--vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php54
-rw-r--r--vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php53
-rw-r--r--vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php34
-rw-r--r--vendor/ramsey/uuid/src/Codec/CodecInterface.php60
-rw-r--r--vendor/ramsey/uuid/src/Codec/GuidStringCodec.php103
-rw-r--r--vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php68
-rw-r--r--vendor/ramsey/uuid/src/Codec/StringCodec.php170
-rw-r--r--vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php108
-rw-r--r--vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php22
-rw-r--r--vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php54
-rw-r--r--vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php58
-rw-r--r--vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php48
-rw-r--r--vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php59
-rw-r--r--vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php42
-rw-r--r--vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php47
-rw-r--r--vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php37
-rw-r--r--vendor/ramsey/uuid/src/DegradedUuid.php116
-rw-r--r--vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php24
-rw-r--r--vendor/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php25
-rw-r--r--vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php24
-rw-r--r--vendor/ramsey/uuid/src/FeatureSet.php335
-rw-r--r--vendor/ramsey/uuid/src/Generator/CombGenerator.php91
-rw-r--r--vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php141
-rw-r--r--vendor/ramsey/uuid/src/Generator/MtRandGenerator.php45
-rw-r--r--vendor/ramsey/uuid/src/Generator/OpenSslGenerator.php43
-rw-r--r--vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php37
-rw-r--r--vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php38
-rw-r--r--vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php39
-rw-r--r--vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php31
-rw-r--r--vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php37
-rw-r--r--vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php62
-rw-r--r--vendor/ramsey/uuid/src/Generator/SodiumRandomGenerator.php41
-rw-r--r--vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php72
-rw-r--r--vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php43
-rw-r--r--vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php59
-rw-r--r--vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php57
-rw-r--r--vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php128
-rw-r--r--vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php32
-rw-r--r--vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php77
-rw-r--r--vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php33
-rw-r--r--vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php29
-rw-r--r--vendor/ramsey/uuid/src/Uuid.php781
-rw-r--r--vendor/ramsey/uuid/src/UuidFactory.php315
-rw-r--r--vendor/ramsey/uuid/src/UuidFactoryInterface.php108
-rw-r--r--vendor/ramsey/uuid/src/UuidInterface.php274
-rw-r--r--vendor/ramsey/uuid/src/functions.php78
-rw-r--r--vendor/react/cache/LICENSE21
-rw-r--r--vendor/react/cache/composer.json41
-rw-r--r--vendor/react/cache/src/ArrayCache.php181
-rw-r--r--vendor/react/cache/src/CacheInterface.php194
-rw-r--r--vendor/react/child-process/LICENSE21
-rw-r--r--vendor/react/child-process/composer.json45
-rw-r--r--vendor/react/child-process/src/Process.php567
-rw-r--r--vendor/react/datagram/LICENSE21
-rw-r--r--vendor/react/datagram/composer.json50
-rw-r--r--vendor/react/datagram/src/Buffer.php114
-rw-r--r--vendor/react/datagram/src/Factory.php149
-rw-r--r--vendor/react/datagram/src/Socket.php142
-rw-r--r--vendor/react/datagram/src/SocketInterface.php29
-rw-r--r--vendor/react/dns/LICENSE21
-rw-r--r--vendor/react/dns/composer.json45
-rw-r--r--vendor/react/dns/src/BadServerException.php7
-rw-r--r--vendor/react/dns/src/Config/Config.php137
-rw-r--r--vendor/react/dns/src/Config/HostsFile.php153
-rw-r--r--vendor/react/dns/src/Model/Message.php230
-rw-r--r--vendor/react/dns/src/Model/Record.php153
-rw-r--r--vendor/react/dns/src/Protocol/BinaryDumper.php199
-rw-r--r--vendor/react/dns/src/Protocol/Parser.php356
-rw-r--r--vendor/react/dns/src/Query/CachingExecutor.php88
-rw-r--r--vendor/react/dns/src/Query/CancellationException.php7
-rw-r--r--vendor/react/dns/src/Query/CoopExecutor.php91
-rw-r--r--vendor/react/dns/src/Query/ExecutorInterface.php43
-rw-r--r--vendor/react/dns/src/Query/FallbackExecutor.php49
-rw-r--r--vendor/react/dns/src/Query/HostsFileExecutor.php89
-rw-r--r--vendor/react/dns/src/Query/Query.php69
-rw-r--r--vendor/react/dns/src/Query/RetryExecutor.php86
-rw-r--r--vendor/react/dns/src/Query/SelectiveTransportExecutor.php85
-rw-r--r--vendor/react/dns/src/Query/TcpTransportExecutor.php367
-rw-r--r--vendor/react/dns/src/Query/TimeoutException.php7
-rw-r--r--vendor/react/dns/src/Query/TimeoutExecutor.php31
-rw-r--r--vendor/react/dns/src/Query/UdpTransportExecutor.php208
-rw-r--r--vendor/react/dns/src/RecordNotFoundException.php7
-rw-r--r--vendor/react/dns/src/Resolver/Factory.php214
-rw-r--r--vendor/react/dns/src/Resolver/Resolver.php147
-rw-r--r--vendor/react/dns/src/Resolver/ResolverInterface.php94
-rw-r--r--vendor/react/event-loop/LICENSE21
-rw-r--r--vendor/react/event-loop/composer.json49
-rw-r--r--vendor/react/event-loop/src/ExtEvLoop.php253
-rw-r--r--vendor/react/event-loop/src/ExtEventLoop.php275
-rw-r--r--vendor/react/event-loop/src/ExtLibevLoop.php201
-rw-r--r--vendor/react/event-loop/src/ExtLibeventLoop.php285
-rw-r--r--vendor/react/event-loop/src/ExtUvLoop.php342
-rw-r--r--vendor/react/event-loop/src/Factory.php75
-rw-r--r--vendor/react/event-loop/src/Loop.php225
-rw-r--r--vendor/react/event-loop/src/LoopInterface.php472
-rw-r--r--vendor/react/event-loop/src/SignalsHandler.php63
-rw-r--r--vendor/react/event-loop/src/StreamSelectLoop.php329
-rw-r--r--vendor/react/event-loop/src/Tick/FutureTickQueue.php60
-rw-r--r--vendor/react/event-loop/src/Timer/Timer.php55
-rw-r--r--vendor/react/event-loop/src/Timer/Timers.php112
-rw-r--r--vendor/react/event-loop/src/TimerInterface.php27
-rw-r--r--vendor/react/http-client/LICENSE19
-rw-r--r--vendor/react/http-client/composer.json30
-rw-r--r--vendor/react/http-client/src/ChunkedStreamDecoder.php207
-rw-r--r--vendor/react/http-client/src/Client.php28
-rw-r--r--vendor/react/http-client/src/Request.php294
-rw-r--r--vendor/react/http-client/src/RequestData.php125
-rw-r--r--vendor/react/http-client/src/Response.php174
-rw-r--r--vendor/react/http/LICENSE21
-rw-r--r--vendor/react/http/composer.json53
-rw-r--r--vendor/react/http/src/Browser.php790
-rw-r--r--vendor/react/http/src/Client/Client.php31
-rw-r--r--vendor/react/http/src/Client/Request.php237
-rw-r--r--vendor/react/http/src/Client/RequestData.php128
-rw-r--r--vendor/react/http/src/HttpServer.php351
-rw-r--r--vendor/react/http/src/Io/BufferedBody.php179
-rw-r--r--vendor/react/http/src/Io/ChunkedDecoder.php175
-rw-r--r--vendor/react/http/src/Io/ChunkedEncoder.php92
-rw-r--r--vendor/react/http/src/Io/CloseProtectionStream.php111
-rw-r--r--vendor/react/http/src/Io/EmptyBodyStream.php142
-rw-r--r--vendor/react/http/src/Io/HttpBodyStream.php182
-rw-r--r--vendor/react/http/src/Io/IniUtil.php48
-rw-r--r--vendor/react/http/src/Io/LengthLimitedStream.php108
-rw-r--r--vendor/react/http/src/Io/MiddlewareRunner.php61
-rw-r--r--vendor/react/http/src/Io/MultipartParser.php328
-rw-r--r--vendor/react/http/src/Io/PauseBufferStream.php188
-rw-r--r--vendor/react/http/src/Io/ReadableBodyStream.php153
-rw-r--r--vendor/react/http/src/Io/RequestHeaderParser.php281
-rw-r--r--vendor/react/http/src/Io/Sender.php160
-rw-r--r--vendor/react/http/src/Io/StreamingServer.php383
-rw-r--r--vendor/react/http/src/Io/Transaction.php303
-rw-r--r--vendor/react/http/src/Io/UploadedFile.php130
-rw-r--r--vendor/react/http/src/Message/Response.php291
-rw-r--r--vendor/react/http/src/Message/ResponseException.php43
-rw-r--r--vendor/react/http/src/Message/ServerRequest.php197
-rw-r--r--vendor/react/http/src/Middleware/LimitConcurrentRequestsMiddleware.php211
-rw-r--r--vendor/react/http/src/Middleware/RequestBodyBufferMiddleware.php70
-rw-r--r--vendor/react/http/src/Middleware/RequestBodyParserMiddleware.php46
-rw-r--r--vendor/react/http/src/Middleware/StreamingRequestMiddleware.php69
-rw-r--r--vendor/react/http/src/Server.php18
-rw-r--r--vendor/react/promise-stream/LICENSE21
-rw-r--r--vendor/react/promise-stream/composer.json47
-rw-r--r--vendor/react/promise-stream/src/UnwrapReadableStream.php137
-rw-r--r--vendor/react/promise-stream/src/UnwrapWritableStream.php164
-rw-r--r--vendor/react/promise-stream/src/functions.php370
-rw-r--r--vendor/react/promise-stream/src/functions_include.php7
-rw-r--r--vendor/react/promise-timer/LICENSE21
-rw-r--r--vendor/react/promise-timer/composer.json44
-rw-r--r--vendor/react/promise-timer/src/TimeoutException.php35
-rw-r--r--vendor/react/promise-timer/src/functions.php330
-rw-r--r--vendor/react/promise-timer/src/functions_include.php7
-rw-r--r--vendor/react/promise/LICENSE24
-rw-r--r--vendor/react/promise/composer.json48
-rw-r--r--vendor/react/promise/src/CancellablePromiseInterface.php17
-rw-r--r--vendor/react/promise/src/CancellationQueue.php55
-rw-r--r--vendor/react/promise/src/Deferred.php65
-rw-r--r--vendor/react/promise/src/Exception/LengthException.php7
-rw-r--r--vendor/react/promise/src/ExtendedPromiseInterface.php98
-rw-r--r--vendor/react/promise/src/FulfilledPromise.php71
-rw-r--r--vendor/react/promise/src/LazyPromise.php66
-rw-r--r--vendor/react/promise/src/Promise.php256
-rw-r--r--vendor/react/promise/src/PromiseInterface.php41
-rw-r--r--vendor/react/promise/src/PromisorInterface.php13
-rw-r--r--vendor/react/promise/src/RejectedPromise.php79
-rw-r--r--vendor/react/promise/src/UnhandledRejectionException.php31
-rw-r--r--vendor/react/promise/src/functions.php407
-rw-r--r--vendor/react/promise/src/functions_include.php5
-rw-r--r--vendor/react/socket/LICENSE21
-rw-r--r--vendor/react/socket/composer.json52
-rw-r--r--vendor/react/socket/src/Connection.php187
-rw-r--r--vendor/react/socket/src/ConnectionInterface.php119
-rw-r--r--vendor/react/socket/src/Connector.php236
-rw-r--r--vendor/react/socket/src/ConnectorInterface.php58
-rw-r--r--vendor/react/socket/src/DnsConnector.php117
-rw-r--r--vendor/react/socket/src/FdServer.php212
-rw-r--r--vendor/react/socket/src/FixedUriConnector.php41
-rw-r--r--vendor/react/socket/src/HappyEyeBallsConnectionBuilder.php333
-rw-r--r--vendor/react/socket/src/HappyEyeBallsConnector.php69
-rw-r--r--vendor/react/socket/src/LimitingServer.php203
-rw-r--r--vendor/react/socket/src/SecureConnector.php122
-rw-r--r--vendor/react/socket/src/SecureServer.php206
-rw-r--r--vendor/react/socket/src/Server.php114
-rw-r--r--vendor/react/socket/src/ServerInterface.php151
-rw-r--r--vendor/react/socket/src/SocketServer.php187
-rw-r--r--vendor/react/socket/src/StreamEncryption.php141
-rw-r--r--vendor/react/socket/src/TcpConnector.php159
-rw-r--r--vendor/react/socket/src/TcpServer.php258
-rw-r--r--vendor/react/socket/src/TimeoutConnector.php51
-rw-r--r--vendor/react/socket/src/UnixConnector.php51
-rw-r--r--vendor/react/socket/src/UnixServer.php154
-rw-r--r--vendor/react/stream/LICENSE21
-rw-r--r--vendor/react/stream/composer.json47
-rw-r--r--vendor/react/stream/src/CompositeStream.php83
-rw-r--r--vendor/react/stream/src/DuplexResourceStream.php227
-rw-r--r--vendor/react/stream/src/DuplexStreamInterface.php39
-rw-r--r--vendor/react/stream/src/ReadableResourceStream.php179
-rw-r--r--vendor/react/stream/src/ReadableStreamInterface.php362
-rw-r--r--vendor/react/stream/src/ThroughStream.php190
-rw-r--r--vendor/react/stream/src/Util.php75
-rw-r--r--vendor/react/stream/src/WritableResourceStream.php168
-rw-r--r--vendor/react/stream/src/WritableStreamInterface.php347
-rw-r--r--vendor/ringcentral/psr7/LICENSE19
-rw-r--r--vendor/ringcentral/psr7/composer.json35
-rw-r--r--vendor/ringcentral/psr7/src/AppendStream.php233
-rw-r--r--vendor/ringcentral/psr7/src/BufferStream.php137
-rw-r--r--vendor/ringcentral/psr7/src/CachingStream.php135
-rw-r--r--vendor/ringcentral/psr7/src/DroppingStream.php41
-rw-r--r--vendor/ringcentral/psr7/src/FnStream.php163
-rw-r--r--vendor/ringcentral/psr7/src/InflateStream.php27
-rw-r--r--vendor/ringcentral/psr7/src/LazyOpenStream.php39
-rw-r--r--vendor/ringcentral/psr7/src/LimitStream.php154
-rw-r--r--vendor/ringcentral/psr7/src/MessageTrait.php167
-rw-r--r--vendor/ringcentral/psr7/src/MultipartStream.php152
-rw-r--r--vendor/ringcentral/psr7/src/NoSeekStream.php21
-rw-r--r--vendor/ringcentral/psr7/src/PumpStream.php165
-rw-r--r--vendor/ringcentral/psr7/src/Request.php146
-rw-r--r--vendor/ringcentral/psr7/src/Response.php129
-rw-r--r--vendor/ringcentral/psr7/src/ServerRequest.php122
-rw-r--r--vendor/ringcentral/psr7/src/Stream.php245
-rw-r--r--vendor/ringcentral/psr7/src/StreamDecoratorTrait.php139
-rw-r--r--vendor/ringcentral/psr7/src/StreamWrapper.php121
-rw-r--r--vendor/ringcentral/psr7/src/Uri.php601
-rw-r--r--vendor/ringcentral/psr7/src/functions.php835
-rw-r--r--vendor/ringcentral/psr7/src/functions_include.php6
-rw-r--r--vendor/symfony/polyfill-ctype/Ctype.php232
-rw-r--r--vendor/symfony/polyfill-ctype/LICENSE19
-rw-r--r--vendor/symfony/polyfill-ctype/bootstrap.php50
-rw-r--r--vendor/symfony/polyfill-ctype/bootstrap80.php46
-rw-r--r--vendor/symfony/polyfill-ctype/composer.json41
-rw-r--r--vendor/symfony/polyfill-intl-idn/Idn.php925
-rw-r--r--vendor/symfony/polyfill-intl-idn/Info.php23
-rw-r--r--vendor/symfony/polyfill-intl-idn/LICENSE19
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php375
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php24
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php8
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php2638
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php308
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php71
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php273
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php5778
-rw-r--r--vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php65
-rw-r--r--vendor/symfony/polyfill-intl-idn/bootstrap.php145
-rw-r--r--vendor/symfony/polyfill-intl-idn/bootstrap80.php125
-rw-r--r--vendor/symfony/polyfill-intl-idn/composer.json44
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/LICENSE19
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Normalizer.php310
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php17
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php945
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php2065
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php876
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php3695
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/bootstrap.php23
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/bootstrap80.php19
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/composer.json39
-rw-r--r--vendor/symfony/polyfill-php72/LICENSE19
-rw-r--r--vendor/symfony/polyfill-php72/Php72.php217
-rw-r--r--vendor/symfony/polyfill-php72/bootstrap.php57
-rw-r--r--vendor/symfony/polyfill-php72/composer.json35
825 files changed, 122798 insertions, 0 deletions
diff --git a/.github/workflows/create-snapshot.yml b/.github/workflows/create-snapshot.yml
new file mode 100644
index 0000000..af5be45
--- /dev/null
+++ b/.github/workflows/create-snapshot.yml
@@ -0,0 +1,39 @@
+name: Create Snapshot
+
+on:
+ schedule:
+ # Every day at 4pm
+ - cron: "0 16 * * *"
+ workflow_dispatch:
+
+jobs:
+ make-snapshot:
+ name: Make a nightly snapshot
+ runs-on: ubuntu-latest
+ if: github.repository == 'Icinga/icinga-php-thirdparty'
+
+ steps:
+ - name: Checkout code base
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ - name: Prepare Git environment
+ run: |
+ git config user.name github-actions[bot]
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
+ echo '{"github-oauth": {"github.com": "${{ secrets.ICINGABOT_TOKEN }}"}}' > auth.json
+ echo 'auth.json' >> .gitignore
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '5.6'
+
+ - name: Create snapshot/nightly
+ if: success()
+ run: bin/make-snapshot.sh snapshot/nightly
+
+ - name: Push snapshot/nightly
+ if: success()
+ run: git push -f origin snapshot/nightly
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2471394
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/vendor/
+/.idea/
+.*.sw[op]
diff --git a/AssetLoader.php b/AssetLoader.php
new file mode 100644
index 0000000..b975001
--- /dev/null
+++ b/AssetLoader.php
@@ -0,0 +1,14 @@
+<?php
+
+class AssetLoader
+{
+ public static function update(Composer\Script\Event $event)
+ {
+ if (! is_dir('asset/js/jquery')) {
+ mkdir('asset/js/jquery', 0775, true);
+ }
+
+ copy('vendor/components/jquery/jquery.js', 'asset/js/jquery/jquery.js');
+ copy('vendor/components/jquery/jquery.min.js', 'asset/js/jquery/jquery.min.js');
+ }
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..58005ec
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2018 Icinga GmbH https://www.icinga.com
+
+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/README.md b/README.md
new file mode 100644
index 0000000..ffc7ab7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,39 @@
+# Icinga PHP Thirdparty
+
+This project bundles all 3rd party PHP libraries used by Icinga Web products into one piece,
+which can be integrated as library into Icinga Web 2.
+
+## Requirements
+
+* [Icinga Web 2](https://github.com/Icinga/icingaweb2) (>= 2.9)
+* PHP (>= 7.2)
+
+## Installation
+
+Please download the latest release and install it in one of your configured library paths. The default library
+path for Icinga Web 2 installations is: `/usr/share/icinga-php`
+
+Download or clone this repository there (e.g. `/usr/share/icinga-php/vendor`) and you're done.
+
+> **Note**: Do NOT install the GIT master, it will not work! Checking out a
+> branch like `stable/0.10.0` or a tag like `v0.10.0` is fine.
+
+### Examples
+
+**Sample Tarball installation**
+
+```sh
+INSTALL_PATH="/usr/share/icinga-php/vendor"
+INSTALL_VERSION="v0.10.0"
+mkdir "$INSTALL_PATH" \
+&& wget -q "https://github.com/Icinga/icinga-php-thirdparty/archive/$INSTALL_VERSION.tar.gz" -O - \
+ | tar xfz - -C "$INSTALL_PATH" --strip-components 1
+```
+
+**Sample GIT installation**
+
+```
+INSTALL_PATH="/usr/share/icinga-php/vendor"
+INSTALL_VERSION="stable/0.10.0"
+git clone https://github.com/Icinga/icinga-php-thirdparty.git "$INSTALL_PATH" --branch "$INSTALL_VERSION"
+```
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100644
index 0000000..db94aeb
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,11 @@
+# Create New Release
+
+ ./bin/make-release.sh <version> [--no-tag]
+
+e.g.
+
+ ./bin/make-release.sh 1.0.0
+
+## Docker Example
+
+ docker run -it -v $(pwd):/tmp/pwd -w /tmp/pwd -v $(realpath ~/.gitconfig):/tmp/user/.gitconfig -e "HOME=/tmp/user" -u $(id -u):$(id -g) dev-docker_web72 bin/make-release.sh 1.0.0 --no-tag
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..fd2726c
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+v0.11.0
diff --git a/asset/css/vendor/diff-table.less b/asset/css/vendor/diff-table.less
new file mode 100644
index 0000000..910b4ee
--- /dev/null
+++ b/asset/css/vendor/diff-table.less
@@ -0,0 +1,185 @@
+/**
+ * This is based on https://github.com/jfcherng/php-diff/blob/6.10.2/example/diff-table.scss
+ *
+ * It's been converted by performing these steps:
+ * - npm install less-plugin-sass2less --save-dev
+ * - ./node_modules/.bin/sass2less -c /usr/share/icinga-php/vendor/vendor/jfcherng/php-diff/example \
+ * diff-table.scss > /usr/share/icinga-php/vendor/asset/css/vendor/diff-table.less
+ * - `@diff-text-color: invert(@diff-bg-color)` though had to be changed to `@diff-text-color: black`.
+ * (`@diff-text-color: spin(@diff-bg-color, 180)` didn't work)
+ */
+
+@diff-bg-color: #fff;
+@diff-text-color: black;
+
+@diff-bg-color-ins-base: #8e8;
+@diff-bg-color-del-base: #e88;
+@diff-bg-color-rep-base: #fbdb65;
+
+@diff-op-highlight-ratio: 90%;
+@diff-op-normal-ratio: 25%;
+
+// emphasized colors for detailed inline difference
+@diff-bg-color-ins-highlight: mix(@diff-bg-color-ins-base, @diff-bg-color, @diff-op-highlight-ratio);
+@diff-bg-color-del-highlight: mix(@diff-bg-color-del-base, @diff-bg-color, @diff-op-highlight-ratio);
+
+// colors for operation rows
+@diff-bg-color-ins: mix(@diff-bg-color-ins-base, @diff-bg-color, @diff-op-normal-ratio);
+@diff-bg-color-del: mix(@diff-bg-color-del-base, @diff-bg-color, @diff-op-normal-ratio);
+@diff-bg-color-rep: mix(@diff-bg-color-rep-base, @diff-bg-color, @diff-op-normal-ratio);
+
+@diff-table-head-color: mix(@diff-bg-color, @diff-text-color, 65%);
+@diff-table-sidebar-color: mix(@diff-bg-color, @diff-text-color, 80%);
+@diff-border-color: @diff-text-color;
+
+// color for the nonexistent block
+// for example, there are a deleted line that has no corresponding one
+@diff-bg-color-none-block: mix(@diff-bg-color, @diff-table-sidebar-color, 80%);
+@diff-bg-color-none-block-alternative: mix(@diff-bg-color, @diff-table-sidebar-color, 55%);
+
+.diff-wrapper.diff {
+ background: repeating-linear-gradient(
+ -45deg,
+ @diff-bg-color-none-block,
+ @diff-bg-color-none-block 0.5em,
+ @diff-bg-color-none-block-alternative 0.5em,
+ @diff-bg-color-none-block-alternative 1em
+ );
+ border-collapse: collapse;
+ border-spacing: 0;
+ border: 1px solid @diff-border-color;
+ color: @diff-text-color;
+ empty-cells: show;
+ font-family: monospace;
+ font-size: 13px;
+ width: 100%;
+ word-break: break-all;
+
+ th {
+ font-weight: 700;
+ }
+
+ td {
+ vertical-align: baseline;
+ }
+
+ td,
+ th {
+ border-collapse: separate;
+ border: none;
+ padding: 1px 2px;
+ background: @diff-bg-color;
+
+ // make empty cell has height
+ &:empty:after {
+ content: " ";
+ visibility: hidden;
+ }
+
+ a {
+ color: #000;
+ cursor: inherit;
+ pointer-events: none;
+ }
+ }
+
+ thead th {
+ background: @diff-table-head-color;
+ border-bottom: 1px solid @diff-border-color;
+ padding: 4px;
+ text-align: left;
+ }
+
+ tbody {
+ &.skipped {
+ border-top: 1px solid @diff-border-color;
+
+ td,
+ th {
+ display: none;
+ }
+ }
+
+ th {
+ background: @diff-table-sidebar-color;
+ border-right: 1px solid @diff-border-color;
+ text-align: right;
+ vertical-align: top;
+ width: 4em;
+
+ &.sign {
+ background: @diff-bg-color;
+ border-right: none;
+ padding: 1px 0;
+ text-align: center;
+ width: 1em;
+
+ &.del {
+ background: @diff-bg-color-del;
+ }
+
+ &.ins {
+ background: @diff-bg-color-ins;
+ }
+ }
+ }
+ }
+
+ &.diff-html {
+ white-space: pre-wrap;
+
+ &.diff-combined {
+ .change.change-rep {
+ .rep {
+ // fixes https://github.com/jfcherng/php-diff/issues/34#issuecomment-671404456
+ white-space: normal;
+ }
+ }
+ }
+
+ .change {
+ &.change-eq {
+ .old,
+ .new {
+ background: @diff-bg-color;
+ }
+ }
+
+ .old {
+ background: @diff-bg-color-del;
+ }
+
+ .new {
+ background: @diff-bg-color-ins;
+ }
+
+ .rep {
+ background: @diff-bg-color-rep;
+ }
+
+ .old,
+ .new,
+ .rep {
+ &.none {
+ background: transparent;
+ cursor: not-allowed;
+ }
+ }
+
+ ins,
+ del {
+ font-weight: bold;
+ text-decoration: none;
+ }
+
+ ins {
+ background: @diff-bg-color-ins-highlight;
+ }
+
+ del {
+ background: @diff-bg-color-del-highlight;
+ }
+ }
+ }
+}
+
diff --git a/asset/js/jquery/jquery.js b/asset/js/jquery/jquery.js
new file mode 100644
index 0000000..fc6c299
--- /dev/null
+++ b/asset/js/jquery/jquery.js
@@ -0,0 +1,10881 @@
+/*!
+ * jQuery JavaScript Library v3.6.0
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright OpenJS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2021-03-02T17:08Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+ return arr.flat.call( array );
+} : function( array ) {
+ return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML <object> elements
+ // (i.e., `typeof document.createElement( "object" ) === "function"`).
+ // We don't want to classify *any* DOM node as a function.
+ // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5
+ // Plus for old WebKit, typeof returns "function" for HTML collections
+ // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756)
+ return typeof obj === "function" && typeof obj.nodeType !== "number" &&
+ typeof obj.item !== "function";
+ };
+
+
+var isWindow = function isWindow( obj ) {
+ return obj != null && obj === obj.window;
+ };
+
+
+var document = window.document;
+
+
+
+ var preservedScriptAttributes = {
+ type: true,
+ src: true,
+ nonce: true,
+ noModule: true
+ };
+
+ function DOMEval( code, node, doc ) {
+ doc = doc || document;
+
+ var i, val,
+ script = doc.createElement( "script" );
+
+ script.text = code;
+ if ( node ) {
+ for ( i in preservedScriptAttributes ) {
+
+ // Support: Firefox 64+, Edge 18+
+ // Some browsers don't support the "nonce" property on scripts.
+ // On the other hand, just using `getAttribute` is not enough as
+ // the `nonce` attribute is reset to an empty string whenever it
+ // becomes browsing-context connected.
+ // See https://github.com/whatwg/html/issues/2369
+ // See https://html.spec.whatwg.org/#nonce-attributes
+ // The `node.getAttribute` check was added for the sake of
+ // `jQuery.globalEval` so that it can fake a nonce-containing node
+ // via an object.
+ val = node[ i ] || node.getAttribute && node.getAttribute( i );
+ if ( val ) {
+ script.setAttribute( i, val );
+ }
+ }
+ }
+ doc.head.appendChild( script ).parentNode.removeChild( script );
+ }
+
+
+function toType( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+
+ // Support: Android <=2.3 only (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+}
+/* global Symbol */
+// Defining this global in .eslintrc.json would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
+
+
+
+var
+ version = "3.6.0",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ };
+
+jQuery.fn = jQuery.prototype = {
+
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+
+ // Return all the elements in a clean array
+ if ( num == null ) {
+ return slice.call( this );
+ }
+
+ // Return just the one element from the set
+ return num < 0 ? this[ num + this.length ] : this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ each: function( callback ) {
+ return jQuery.each( this, callback );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ } ) );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ even: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return ( i + 1 ) % 2;
+ } ) );
+ },
+
+ odd: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return i % 2;
+ } ) );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor();
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: arr.sort,
+ splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[ 0 ] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !isFunction( target ) ) {
+ target = {};
+ }
+
+ // Extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+
+ // Only deal with non-null/undefined values
+ if ( ( options = arguments[ i ] ) != null ) {
+
+ // Extend the base object
+ for ( name in options ) {
+ copy = options[ name ];
+
+ // Prevent Object.prototype pollution
+ // Prevent never-ending loop
+ if ( name === "__proto__" || target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = Array.isArray( copy ) ) ) ) {
+ src = target[ name ];
+
+ // Ensure proper type for the source value
+ if ( copyIsArray && !Array.isArray( src ) ) {
+ clone = [];
+ } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
+ clone = {};
+ } else {
+ clone = src;
+ }
+ copyIsArray = false;
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend( {
+
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ isPlainObject: function( obj ) {
+ var proto, Ctor;
+
+ // Detect obvious negatives
+ // Use toString instead of jQuery.type to catch host objects
+ if ( !obj || toString.call( obj ) !== "[object Object]" ) {
+ return false;
+ }
+
+ proto = getProto( obj );
+
+ // Objects with no prototype (e.g., `Object.create( null )`) are plain
+ if ( !proto ) {
+ return true;
+ }
+
+ // Objects with prototype are plain iff they were constructed by a global Object function
+ Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+ return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ // Evaluates a script in a provided context; falls back to the global one
+ // if not specified.
+ globalEval: function( code, options, doc ) {
+ DOMEval( code, { nonce: options && options.nonce }, doc );
+ },
+
+ each: function( obj, callback ) {
+ var length, i = 0;
+
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArrayLike( Object( arr ) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
+ },
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var length, value,
+ i = 0,
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return flat( ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+} );
+
+if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
+
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+ function( _i, name ) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+ } );
+
+function isArrayLike( obj ) {
+
+ // Support: real iOS 8.2 only (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
+ type = toType( obj );
+
+ if ( isFunction( obj ) || isWindow( obj ) ) {
+ return false;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.3.6
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://js.foundation/
+ *
+ * Date: 2021-02-16
+ */
+( function( window ) {
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ nonnativeSelectorCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // Instance methods
+ hasOwn = ( {} ).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ pushNative = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+
+ // Use a stripped-down indexOf as it's faster than native
+ // https://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[ i ] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
+ "ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
+ identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
+ "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+
+ // "Attribute values must be CSS identifiers [capture 5]
+ // or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
+ whitespace + "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
+ whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
+ "*" ),
+ rdescend = new RegExp( whitespace + "|>" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+ whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+ whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace +
+ "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rhtml = /HTML$/i,
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+
+ // CSS escapes
+ // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+ funescape = function( escape, nonHex ) {
+ var high = "0x" + escape.slice( 1 ) - 0x10000;
+
+ return nonHex ?
+
+ // Strip the backslash prefix from a non-hex escape sequence
+ nonHex :
+
+ // Replace a hexadecimal escape sequence with the encoded Unicode code point
+ // Support: IE <=11+
+ // For values outside the Basic Multilingual Plane (BMP), manually construct a
+ // surrogate pair
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // CSS string/identifier serialization
+ // https://drafts.csswg.org/cssom/#common-serializing-idioms
+ rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
+ fcssescape = function( ch, asCodePoint ) {
+ if ( asCodePoint ) {
+
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+ if ( ch === "\0" ) {
+ return "\uFFFD";
+ }
+
+ // Control characters and (dependent upon position) numbers get escaped as code points
+ return ch.slice( 0, -1 ) + "\\" +
+ ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ }
+
+ // Other potentially-special ASCII characters get backslash-escaped
+ return "\\" + ch;
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ },
+
+ inDisabledFieldset = addCombinator(
+ function( elem ) {
+ return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
+ },
+ { dir: "parentNode", next: "legend" }
+ );
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ ( arr = slice.call( preferredDoc.childNodes ) ),
+ preferredDoc.childNodes
+ );
+
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ // eslint-disable-next-line no-unused-expressions
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ pushNative.apply( target, slice.call( els ) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+
+ // Can't trust NodeList.length
+ while ( ( target[ j++ ] = els[ i++ ] ) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var m, i, elem, nid, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
+
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
+
+ results = results || [];
+
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
+ setDocument( context );
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
+
+ // ID selector
+ if ( ( m = match[ 1 ] ) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( ( elem = context.getElementById( m ) ) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+
+ // Element context
+ } else {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && ( elem = newContext.getElementById( m ) ) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Type selector
+ } else if ( match[ 2 ] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Class selector
+ } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !nonnativeSelectorCache[ selector + " " ] &&
+ ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
+
+ // Support: IE 8 only
+ // Exclude object elements
+ ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
+
+ newSelector = selector;
+ newContext = context;
+
+ // qSA considers elements outside a scoping root when evaluating child or
+ // descendant combinators, which is not what we want.
+ // In such cases, we work around the behavior by prefixing every selector in the
+ // list with an ID selector referencing the scope context.
+ // The technique has to be used as well when a leading combinator is used
+ // as such selectors are not recognized by querySelectorAll.
+ // Thanks to Andrew Dupont for this technique.
+ if ( nodeType === 1 &&
+ ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+
+ // We can use :scope instead of the ID hack if the browser
+ // supports it & if we're not changing the context.
+ if ( newContext !== context || !support.scope ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( ( nid = context.getAttribute( "id" ) ) ) {
+ nid = nid.replace( rcssescape, fcssescape );
+ } else {
+ context.setAttribute( "id", ( nid = expando ) );
+ }
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ while ( i-- ) {
+ groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+ toSelector( groups[ i ] );
+ }
+ newSelector = groups.join( "," );
+ }
+
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ nonnativeSelectorCache( selector, true );
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return ( cache[ key + " " ] = value );
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created element and returns a boolean result
+ */
+function assert( fn ) {
+ var el = document.createElement( "fieldset" );
+
+ try {
+ return !!fn( el );
+ } catch ( e ) {
+ return false;
+ } finally {
+
+ // Remove from its parent by default
+ if ( el.parentNode ) {
+ el.parentNode.removeChild( el );
+ }
+
+ // release memory in IE
+ el = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split( "|" ),
+ i = arr.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[ i ] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ a.sourceIndex - b.sourceIndex;
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( ( cur = cur.nextSibling ) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return ( name === "input" || name === "button" ) && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+
+ // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+ return function( elem ) {
+
+ // Only certain elements can match :enabled or :disabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
+ if ( "form" in elem ) {
+
+ // Check for inherited disabledness on relevant non-disabled elements:
+ // * listed form-associated elements in a disabled fieldset
+ // https://html.spec.whatwg.org/multipage/forms.html#category-listed
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
+ // * option elements in a disabled optgroup
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
+ // All such elements have a "form" property.
+ if ( elem.parentNode && elem.disabled === false ) {
+
+ // Option elements defer to a parent optgroup if present
+ if ( "label" in elem ) {
+ if ( "label" in elem.parentNode ) {
+ return elem.parentNode.disabled === disabled;
+ } else {
+ return elem.disabled === disabled;
+ }
+ }
+
+ // Support: IE 6 - 11
+ // Use the isDisabled shortcut property to check for disabled fieldset ancestors
+ return elem.isDisabled === disabled ||
+
+ // Where there is no isDisabled, check manually
+ /* jshint -W018 */
+ elem.isDisabled !== !disabled &&
+ inDisabledFieldset( elem ) === disabled;
+ }
+
+ return elem.disabled === disabled;
+
+ // Try to winnow out elements that can't be disabled before trusting the disabled property.
+ // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
+ // even exist on them, let alone have a boolean value.
+ } else if ( "label" in elem ) {
+ return elem.disabled === disabled;
+ }
+
+ // Remaining elements are neither :enabled nor :disabled
+ return false;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction( function( argument ) {
+ argument = +argument;
+ return markFunction( function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
+ seed[ j ] = !( matches[ j ] = seed[ j ] );
+ }
+ }
+ } );
+ } );
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ var namespace = elem && elem.namespaceURI,
+ docElem = elem && ( elem.ownerDocument || elem ).documentElement;
+
+ // Support: IE <=8
+ // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
+ // https://bugs.jquery.com/ticket/4833
+ return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, subWindow,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // Return early if doc is invalid or already selected
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Update global variables
+ document = doc;
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9 - 11+, Edge 12 - 18+
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( preferredDoc != document &&
+ ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
+
+ // Support: IE 11, Edge
+ if ( subWindow.addEventListener ) {
+ subWindow.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( subWindow.attachEvent ) {
+ subWindow.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
+ // Safari 4 - 5 only, Opera <=11.6 - 12.x only
+ // IE/Edge & older browsers don't support the :scope pseudo-class.
+ // Support: Safari 6.0 only
+ // Safari 6.0 supports :scope but it's an alias of :root there.
+ support.scope = assert( function( el ) {
+ docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
+ return typeof el.querySelectorAll !== "undefined" &&
+ !el.querySelectorAll( ":scope fieldset div" ).length;
+ } );
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert( function( el ) {
+ el.className = "i";
+ return !el.getAttribute( "className" );
+ } );
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert( function( el ) {
+ el.appendChild( document.createComment( "" ) );
+ return !el.getElementsByTagName( "*" ).length;
+ } );
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programmatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert( function( el ) {
+ docElem.appendChild( el ).id = expando;
+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
+ } );
+
+ // ID filter and find
+ if ( support.getById ) {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute( "id" ) === attrId;
+ };
+ };
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var elem = context.getElementById( id );
+ return elem ? [ elem ] : [];
+ }
+ };
+ } else {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" &&
+ elem.getAttributeNode( "id" );
+ return node && node.value === attrId;
+ };
+ };
+
+ // Support: IE 6 - 7 only
+ // getElementById is not reliable as a find shortcut
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var node, i, elems,
+ elem = context.getElementById( id );
+
+ if ( elem ) {
+
+ // Verify the id attribute
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+
+ // Fall back on getElementsByName
+ elems = context.getElementsByName( id );
+ i = 0;
+ while ( ( elem = elems[ i++ ] ) ) {
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+ }
+ }
+
+ return [];
+ }
+ };
+ }
+
+ // Tag
+ Expr.find[ "TAG" ] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See https://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert( function( el ) {
+
+ var input;
+
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // https://bugs.jquery.com/ticket/12359
+ docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+ "<option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !el.querySelectorAll( "[selected]" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push( "~=" );
+ }
+
+ // Support: IE 11+, Edge 15 - 18+
+ // IE 11/Edge don't find elements on a `[name='']` query in some cases.
+ // Adding a temporary attribute to the document before the selection works
+ // around the issue.
+ // Interestingly, IE 10 & older don't seem to have the issue.
+ input = document.createElement( "input" );
+ input.setAttribute( "name", "" );
+ el.appendChild( input );
+ if ( !el.querySelectorAll( "[name='']" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+ whitespace + "*(?:''|\"\")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !el.querySelectorAll( ":checked" ).length ) {
+ rbuggyQSA.push( ":checked" );
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibling-combinator selector` fails
+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push( ".#.+[+~]" );
+ }
+
+ // Support: Firefox <=3.6 - 5 only
+ // Old Firefox doesn't throw on a badly-escaped identifier.
+ el.querySelectorAll( "\\\f" );
+ rbuggyQSA.push( "[\\r\\n\\f]" );
+ } );
+
+ assert( function( el ) {
+ el.innerHTML = "<a href='' disabled='disabled'></a>" +
+ "<select disabled='disabled'><option/></select>";
+
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = document.createElement( "input" );
+ input.setAttribute( "type", "hidden" );
+ el.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( el.querySelectorAll( "[name=d]" ).length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: IE9-11+
+ // IE's :disabled selector does not pick up the children of disabled fieldsets
+ docElem.appendChild( el ).disabled = true;
+ if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: Opera 10 - 11 only
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ el.querySelectorAll( "*,:x" );
+ rbuggyQSA.push( ",.*:" );
+ } );
+ }
+
+ if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector ) ) ) ) {
+
+ assert( function( el ) {
+
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( el, "*" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( el, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ } );
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully self-exclusive
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ) );
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( ( b = b.parentNode ) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
+
+ // Choose the first element that is related to our preferred document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( a == document || a.ownerDocument == preferredDoc &&
+ contains( preferredDoc, a ) ) {
+ return -1;
+ }
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( b == document || b.ownerDocument == preferredDoc &&
+ contains( preferredDoc, b ) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ return a == document ? -1 :
+ b == document ? 1 :
+ /* eslint-enable eqeqeq */
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( ( cur = cur.parentNode ) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( ( cur = cur.parentNode ) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[ i ] === bp[ i ] ) {
+ i++;
+ }
+
+ return i ?
+
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[ i ], bp[ i ] ) :
+
+ // Otherwise nodes in our document sort first
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ ap[ i ] == preferredDoc ? -1 :
+ bp[ i ] == preferredDoc ? 1 :
+ /* eslint-enable eqeqeq */
+ 0;
+ };
+
+ return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ setDocument( elem );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ !nonnativeSelectorCache[ expr + " " ] &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch ( e ) {
+ nonnativeSelectorCache( expr, true );
+ }
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( context.ownerDocument || context ) != document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( elem.ownerDocument || elem ) != document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.escape = function( sel ) {
+ return ( sel + "" ).replace( rcssescape, fcssescape );
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+
+ // If no nodeType, this is expected to be an array
+ while ( ( node = elem[ i++ ] ) ) {
+
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[ 1 ] = match[ 1 ].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
+ match[ 5 ] || "" ).replace( runescape, funescape );
+
+ if ( match[ 2 ] === "~=" ) {
+ match[ 3 ] = " " + match[ 3 ] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[ 1 ] = match[ 1 ].toLowerCase();
+
+ if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
+
+ // nth-* requires argument
+ if ( !match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[ 4 ] = +( match[ 4 ] ?
+ match[ 5 ] + ( match[ 6 ] || 1 ) :
+ 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+ match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[ 6 ] && match[ 2 ];
+
+ if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[ 3 ] ) {
+ match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+
+ // Get excess from tokenize (recursively)
+ ( excess = tokenize( unquoted, true ) ) &&
+
+ // advance to the next closing parenthesis
+ ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
+
+ // excess is a negative index
+ match[ 0 ] = match[ 0 ].slice( 0, excess );
+ match[ 2 ] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() {
+ return true;
+ } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ ( pattern = new RegExp( "(^|" + whitespace +
+ ")" + className + "(" + whitespace + "|$)" ) ) && classCache(
+ className, function( elem ) {
+ return pattern.test(
+ typeof elem.className === "string" && elem.className ||
+ typeof elem.getAttribute !== "undefined" &&
+ elem.getAttribute( "class" ) ||
+ ""
+ );
+ } );
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ /* eslint-disable max-len */
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ /* eslint-enable max-len */
+
+ };
+ },
+
+ "CHILD": function( type, what, _argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, _context, xml ) {
+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType,
+ diff = false;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( ( node = node[ dir ] ) ) {
+ if ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) {
+
+ return false;
+ }
+ }
+
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+
+ // Seek `elem` from a previously-cached index
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && cache[ 2 ];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ } else {
+
+ // Use previously-cached element index if available
+ if ( useCache ) {
+
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+
+ // Use the same loop as above to seek `elem` from the start
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ if ( ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) &&
+ ++diff ) {
+
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ outerCache = node[ expando ] ||
+ ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ uniqueCache[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction( function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[ i ] );
+ seed[ idx ] = !( matches[ idx ] = matched[ i ] );
+ }
+ } ) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+
+ // Potentially complex pseudos
+ "not": markFunction( function( selector ) {
+
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction( function( seed, matches, _context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ seed[ i ] = !( matches[ i ] = elem );
+ }
+ }
+ } ) :
+ function( elem, _context, xml ) {
+ input[ 0 ] = elem;
+ matcher( input, null, xml, results );
+
+ // Don't keep the element (issue #299)
+ input[ 0 ] = null;
+ return !results.pop();
+ };
+ } ),
+
+ "has": markFunction( function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ } ),
+
+ "contains": markFunction( function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
+ };
+ } ),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+
+ // lang value must be a valid identifier
+ if ( !ridentifier.test( lang || "" ) ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( ( elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
+ return false;
+ };
+ } ),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement &&
+ ( !document.hasFocus || document.hasFocus() ) &&
+ !!( elem.type || elem.href || ~elem.tabIndex );
+ },
+
+ // Boolean properties
+ "enabled": createDisabledPseudo( false ),
+ "disabled": createDisabledPseudo( true ),
+
+ "checked": function( elem ) {
+
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return ( nodeName === "input" && !!elem.checked ) ||
+ ( nodeName === "option" && !!elem.selected );
+ },
+
+ "selected": function( elem ) {
+
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ // eslint-disable-next-line no-unused-expressions
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos[ "empty" ]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( ( attr = elem.getAttribute( "type" ) ) == null ||
+ attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo( function() {
+ return [ 0 ];
+ } ),
+
+ "last": createPositionalPseudo( function( _matchIndexes, length ) {
+ return [ length - 1 ];
+ } ),
+
+ "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ } ),
+
+ "even": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "odd": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ?
+ argument + length :
+ argument > length ?
+ length :
+ argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } )
+ }
+};
+
+Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
+ if ( match ) {
+
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[ 0 ].length ) || soFar;
+ }
+ groups.push( ( tokens = [] ) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( ( match = rcombinators.exec( soFar ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+
+ // Cast descendant combinators to space
+ type: match[ 0 ].replace( rtrim, " " )
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
+ ( match = preFilters[ type ]( match ) ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+ type: type,
+ matches: match
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[ i ].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ skip = combinator.next,
+ key = skip || dir,
+ checkNonElements = base && key === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ return false;
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, uniqueCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
+ if ( xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] ||
+ ( outerCache[ elem.uniqueID ] = {} );
+
+ if ( skip && skip === elem.nodeName.toLowerCase() ) {
+ elem = elem[ dir ] || elem;
+ } else if ( ( oldCache = uniqueCache[ key ] ) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return ( newCache[ 2 ] = oldCache[ 2 ] );
+ } else {
+
+ // Reuse newcache so results back-propagate to previous elements
+ uniqueCache[ key ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[ i ]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[ 0 ];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[ i ], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction( function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts(
+ selector || "*",
+ context.nodeType ? [ context ] : context,
+ []
+ ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( ( elem = temp[ i ] ) ) {
+ matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) ) {
+
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( ( matcherIn[ i ] = elem ) );
+ }
+ }
+ postFinder( null, ( matcherOut = [] ), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) &&
+ ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
+
+ seed[ temp ] = !( results[ temp ] = elem );
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ } );
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[ 0 ].type ],
+ implicitRelative = leadingRelative || Expr.relative[ " " ],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ ( checkContext = context ).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[ j ].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens
+ .slice( 0, i - 1 )
+ .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
+ len = elems.length;
+
+ if ( outermost ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ outermostContext = context == document || context || outermost;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( !context && elem.ownerDocument != document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
+ while ( ( matcher = elementMatchers[ j++ ] ) ) {
+ if ( matcher( elem, context || document, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+
+ // They will have gone through all possible matchers
+ if ( ( elem = !matcher && elem ) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
+ matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( ( matcher = setMatchers[ j++ ] ) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
+ setMatched[ i ] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[ i ] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache(
+ selector,
+ matcherFromGroupMatchers( elementMatchers, setMatchers )
+ );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( ( selector = compiled.selector || selector ) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
+ if ( match.length === 1 ) {
+
+ // Reduce context if the leading compound selector is an ID
+ tokens = match[ 0 ] = match[ 0 ].slice( 0 );
+ if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
+ context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+
+ context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
+ .replace( runescape, funescape ), context ) || [] )[ 0 ];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[ i ];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ ( type = token.type ) ] ) {
+ break;
+ }
+ if ( ( find = Expr.find[ type ] ) ) {
+
+ // Search, expanding context for leading sibling combinators
+ if ( ( seed = find(
+ token.matches[ 0 ].replace( runescape, funescape ),
+ rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
+ context
+ ) ) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert( function( el ) {
+
+ // Should return 1, but returns 4 (following)
+ return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
+} );
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert( function( el ) {
+ el.innerHTML = "<a href='#'></a>";
+ return el.firstChild.getAttribute( "href" ) === "#";
+} ) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ } );
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert( function( el ) {
+ el.innerHTML = "<input/>";
+ el.firstChild.setAttribute( "value", "" );
+ return el.firstChild.getAttribute( "value" ) === "";
+} ) ) {
+ addHandle( "value", function( elem, _name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ } );
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert( function( el ) {
+ return el.getAttribute( "disabled" ) == null;
+} ) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+ }
+ } );
+}
+
+return Sizzle;
+
+} )( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+
+// Deprecated
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+jQuery.escapeSelector = Sizzle.escape;
+
+
+
+
+var dir = function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+};
+
+
+var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+};
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+
+
+function nodeName( elem, name ) {
+
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+
+}
+var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
+
+
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ return !!qualifier.call( elem, i, elem ) !== not;
+ } );
+ }
+
+ // Single element
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ } );
+ }
+
+ // Arraylike of elements (jQuery, arguments, Array)
+ if ( typeof qualifier !== "string" ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
+ } );
+ }
+
+ // Filtered directly for both simple and complex selectors
+ return jQuery.filter( qualifier, elements, not );
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ if ( elems.length === 1 && elem.nodeType === 1 ) {
+ return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
+ }
+
+ return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ } ) );
+};
+
+jQuery.fn.extend( {
+ find: function( selector ) {
+ var i, ret,
+ len = this.length,
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter( function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ } ) );
+ }
+
+ ret = this.pushStack( [] );
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ return len > 1 ? jQuery.uniqueSort( ret ) : ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], false ) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], true ) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+} );
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ // Shortcut simple #id case for speed
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
+
+ init = jQuery.fn.init = function( selector, context, root ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Method init() accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector[ 0 ] === "<" &&
+ selector[ selector.length - 1 ] === ">" &&
+ selector.length >= 3 ) {
+
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && ( match[ 1 ] || !context ) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[ 1 ] ) {
+ context = context instanceof jQuery ? context[ 0 ] : context;
+
+ // Option to run scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[ 1 ],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+
+ // Properties of context are called as methods if possible
+ if ( isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[ 2 ] );
+
+ if ( elem ) {
+
+ // Inject the element directly into the jQuery object
+ this[ 0 ] = elem;
+ this.length = 1;
+ }
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || root ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this[ 0 ] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( isFunction( selector ) ) {
+ return root.ready !== undefined ?
+ root.ready( selector ) :
+
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+ // Methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend( {
+ has: function( target ) {
+ var targets = jQuery( target, this ),
+ l = targets.length;
+
+ return this.filter( function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[ i ] ) ) {
+ return true;
+ }
+ }
+ } );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ targets = typeof selectors !== "string" && jQuery( selectors );
+
+ // Positional selectors never match, since there's no _selection_ context
+ if ( !rneedsContext.test( selectors ) ) {
+ for ( ; i < l; i++ ) {
+ for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
+
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && ( targets ?
+ targets.index( cur ) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+ },
+
+ // Determine the position of an element within the set
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // Index in selector
+ if ( typeof elem === "string" ) {
+ return indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.uniqueSort(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ }
+} );
+
+function sibling( cur, dir ) {
+ while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
+ return cur;
+}
+
+jQuery.each( {
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, _i, until ) {
+ return dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, _i, until ) {
+ return dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, _i, until ) {
+ return dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return siblings( elem.firstChild );
+ },
+ contents: function( elem ) {
+ if ( elem.contentDocument != null &&
+
+ // Support: IE 11+
+ // <object> elements with no `data` attribute has an object
+ // `contentDocument` with a `null` prototype.
+ getProto( elem.contentDocument ) ) {
+
+ return elem.contentDocument;
+ }
+
+ // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
+ // Treat the template element as a regular one in browsers that
+ // don't support it.
+ if ( nodeName( elem, "template" ) ) {
+ elem = elem.content || elem;
+ }
+
+ return jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var matched = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ matched = jQuery.filter( selector, matched );
+ }
+
+ if ( this.length > 1 ) {
+
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ jQuery.uniqueSort( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+} );
+var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
+
+
+
+// Convert String-formatted options into Object-formatted ones
+function createOptions( options ) {
+ var object = {};
+ jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ } );
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ createOptions( options ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+
+ // Last fire value for non-forgettable lists
+ memory,
+
+ // Flag to know if list was already fired
+ fired,
+
+ // Flag to prevent firing
+ locked,
+
+ // Actual callback list
+ list = [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
+ // Fire callbacks
+ fire = function() {
+
+ // Enforce single-firing
+ locked = locked || options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
+ }
+ }
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
+ firing = false;
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
+ list = [];
+
+ // Otherwise, this object is spent
+ } else {
+ list = "";
+ }
+ }
+ },
+
+ // Actual Callbacks object
+ self = {
+
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ if ( isFunction( arg ) ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && toType( arg ) !== "string" ) {
+
+ // Inspect recursively
+ add( arg );
+ }
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Remove a callback from the list
+ remove: function() {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ } );
+ return this;
+ },
+
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ?
+ jQuery.inArray( fn, list ) > -1 :
+ list.length > 0;
+ },
+
+ // Remove all callbacks from the list
+ empty: function() {
+ if ( list ) {
+ list = [];
+ }
+ return this;
+ },
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
+ disable: function() {
+ locked = queue = [];
+ list = memory = "";
+ return this;
+ },
+ disabled: function() {
+ return !list;
+ },
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
+ lock: function() {
+ locked = queue = [];
+ if ( !memory && !firing ) {
+ list = memory = "";
+ }
+ return this;
+ },
+ locked: function() {
+ return !!locked;
+ },
+
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( !locked ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ queue.push( args );
+ if ( !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+function Identity( v ) {
+ return v;
+}
+function Thrower( ex ) {
+ throw ex;
+}
+
+function adoptValue( value, resolve, reject, noValue ) {
+ var method;
+
+ try {
+
+ // Check for promise aspect first to privilege synchronous behavior
+ if ( value && isFunction( ( method = value.promise ) ) ) {
+ method.call( value ).done( resolve ).fail( reject );
+
+ // Other thenables
+ } else if ( value && isFunction( ( method = value.then ) ) ) {
+ method.call( value, resolve, reject );
+
+ // Other non-thenables
+ } else {
+
+ // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
+ // * false: [ value ].slice( 0 ) => resolve( value )
+ // * true: [ value ].slice( 1 ) => resolve()
+ resolve.apply( undefined, [ value ].slice( noValue ) );
+ }
+
+ // For Promises/A+, convert exceptions into rejections
+ // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+ // Deferred#then to conditionally suppress rejection.
+ } catch ( value ) {
+
+ // Support: Android 4.0 only
+ // Strict mode functions invoked without .call/.apply get global-object context
+ reject.apply( undefined, [ value ] );
+ }
+}
+
+jQuery.extend( {
+
+ Deferred: function( func ) {
+ var tuples = [
+
+ // action, add listener, callbacks,
+ // ... .then handlers, argument index, [final state]
+ [ "notify", "progress", jQuery.Callbacks( "memory" ),
+ jQuery.Callbacks( "memory" ), 2 ],
+ [ "resolve", "done", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 0, "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 1, "rejected" ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ "catch": function( fn ) {
+ return promise.then( null, fn );
+ },
+
+ // Keep pipe for back-compat
+ pipe: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+
+ return jQuery.Deferred( function( newDefer ) {
+ jQuery.each( tuples, function( _i, tuple ) {
+
+ // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+ var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+ // deferred.progress(function() { bind to newDefer or newDefer.notify })
+ // deferred.done(function() { bind to newDefer or newDefer.resolve })
+ // deferred.fail(function() { bind to newDefer or newDefer.reject })
+ deferred[ tuple[ 1 ] ]( function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && isFunction( returned.promise ) ) {
+ returned.promise()
+ .progress( newDefer.notify )
+ .done( newDefer.resolve )
+ .fail( newDefer.reject );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ](
+ this,
+ fn ? [ returned ] : arguments
+ );
+ }
+ } );
+ } );
+ fns = null;
+ } ).promise();
+ },
+ then: function( onFulfilled, onRejected, onProgress ) {
+ var maxDepth = 0;
+ function resolve( depth, deferred, handler, special ) {
+ return function() {
+ var that = this,
+ args = arguments,
+ mightThrow = function() {
+ var returned, then;
+
+ // Support: Promises/A+ section 2.3.3.3.3
+ // https://promisesaplus.com/#point-59
+ // Ignore double-resolution attempts
+ if ( depth < maxDepth ) {
+ return;
+ }
+
+ returned = handler.apply( that, args );
+
+ // Support: Promises/A+ section 2.3.1
+ // https://promisesaplus.com/#point-48
+ if ( returned === deferred.promise() ) {
+ throw new TypeError( "Thenable self-resolution" );
+ }
+
+ // Support: Promises/A+ sections 2.3.3.1, 3.5
+ // https://promisesaplus.com/#point-54
+ // https://promisesaplus.com/#point-75
+ // Retrieve `then` only once
+ then = returned &&
+
+ // Support: Promises/A+ section 2.3.4
+ // https://promisesaplus.com/#point-64
+ // Only check objects and functions for thenability
+ ( typeof returned === "object" ||
+ typeof returned === "function" ) &&
+ returned.then;
+
+ // Handle a returned thenable
+ if ( isFunction( then ) ) {
+
+ // Special processors (notify) just wait for resolution
+ if ( special ) {
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special )
+ );
+
+ // Normal processors (resolve) also hook into progress
+ } else {
+
+ // ...and disregard older resolution values
+ maxDepth++;
+
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special ),
+ resolve( maxDepth, deferred, Identity,
+ deferred.notifyWith )
+ );
+ }
+
+ // Handle all other returned values
+ } else {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Identity ) {
+ that = undefined;
+ args = [ returned ];
+ }
+
+ // Process the value(s)
+ // Default process is resolve
+ ( special || deferred.resolveWith )( that, args );
+ }
+ },
+
+ // Only normal processors (resolve) catch and reject exceptions
+ process = special ?
+ mightThrow :
+ function() {
+ try {
+ mightThrow();
+ } catch ( e ) {
+
+ if ( jQuery.Deferred.exceptionHook ) {
+ jQuery.Deferred.exceptionHook( e,
+ process.stackTrace );
+ }
+
+ // Support: Promises/A+ section 2.3.3.3.4.1
+ // https://promisesaplus.com/#point-61
+ // Ignore post-resolution exceptions
+ if ( depth + 1 >= maxDepth ) {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Thrower ) {
+ that = undefined;
+ args = [ e ];
+ }
+
+ deferred.rejectWith( that, args );
+ }
+ }
+ };
+
+ // Support: Promises/A+ section 2.3.3.3.1
+ // https://promisesaplus.com/#point-57
+ // Re-resolve promises immediately to dodge false rejection from
+ // subsequent errors
+ if ( depth ) {
+ process();
+ } else {
+
+ // Call an optional hook to record the stack, in case of exception
+ // since it's otherwise lost when execution goes async
+ if ( jQuery.Deferred.getStackHook ) {
+ process.stackTrace = jQuery.Deferred.getStackHook();
+ }
+ window.setTimeout( process );
+ }
+ };
+ }
+
+ return jQuery.Deferred( function( newDefer ) {
+
+ // progress_handlers.add( ... )
+ tuples[ 0 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onProgress ) ?
+ onProgress :
+ Identity,
+ newDefer.notifyWith
+ )
+ );
+
+ // fulfilled_handlers.add( ... )
+ tuples[ 1 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onFulfilled ) ?
+ onFulfilled :
+ Identity
+ )
+ );
+
+ // rejected_handlers.add( ... )
+ tuples[ 2 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onRejected ) ?
+ onRejected :
+ Thrower
+ )
+ );
+ } ).promise();
+ },
+
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 5 ];
+
+ // promise.progress = list.add
+ // promise.done = list.add
+ // promise.fail = list.add
+ promise[ tuple[ 1 ] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(
+ function() {
+
+ // state = "resolved" (i.e., fulfilled)
+ // state = "rejected"
+ state = stateString;
+ },
+
+ // rejected_callbacks.disable
+ // fulfilled_callbacks.disable
+ tuples[ 3 - i ][ 2 ].disable,
+
+ // rejected_handlers.disable
+ // fulfilled_handlers.disable
+ tuples[ 3 - i ][ 3 ].disable,
+
+ // progress_callbacks.lock
+ tuples[ 0 ][ 2 ].lock,
+
+ // progress_handlers.lock
+ tuples[ 0 ][ 3 ].lock
+ );
+ }
+
+ // progress_handlers.fire
+ // fulfilled_handlers.fire
+ // rejected_handlers.fire
+ list.add( tuple[ 3 ].fire );
+
+ // deferred.notify = function() { deferred.notifyWith(...) }
+ // deferred.resolve = function() { deferred.resolveWith(...) }
+ // deferred.reject = function() { deferred.rejectWith(...) }
+ deferred[ tuple[ 0 ] ] = function() {
+ deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
+ return this;
+ };
+
+ // deferred.notifyWith = list.fireWith
+ // deferred.resolveWith = list.fireWith
+ // deferred.rejectWith = list.fireWith
+ deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+ } );
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( singleValue ) {
+ var
+
+ // count of uncompleted subordinates
+ remaining = arguments.length,
+
+ // count of unprocessed arguments
+ i = remaining,
+
+ // subordinate fulfillment data
+ resolveContexts = Array( i ),
+ resolveValues = slice.call( arguments ),
+
+ // the primary Deferred
+ primary = jQuery.Deferred(),
+
+ // subordinate callback factory
+ updateFunc = function( i ) {
+ return function( value ) {
+ resolveContexts[ i ] = this;
+ resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( !( --remaining ) ) {
+ primary.resolveWith( resolveContexts, resolveValues );
+ }
+ };
+ };
+
+ // Single- and empty arguments are adopted like Promise.resolve
+ if ( remaining <= 1 ) {
+ adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,
+ !remaining );
+
+ // Use .then() to unwrap secondary thenables (cf. gh-3000)
+ if ( primary.state() === "pending" ||
+ isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+
+ return primary.then();
+ }
+ }
+
+ // Multiple arguments are aggregated like Promise.all array elements
+ while ( i-- ) {
+ adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );
+ }
+
+ return primary.promise();
+ }
+} );
+
+
+// These usually indicate a programmer mistake during development,
+// warn about them ASAP rather than swallowing them by default.
+var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+
+jQuery.Deferred.exceptionHook = function( error, stack ) {
+
+ // Support: IE 8 - 9 only
+ // Console exists when dev tools are open, which can happen at any time
+ if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
+ window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+ }
+};
+
+
+
+
+jQuery.readyException = function( error ) {
+ window.setTimeout( function() {
+ throw error;
+ } );
+};
+
+
+
+
+// The deferred used on DOM ready
+var readyList = jQuery.Deferred();
+
+jQuery.fn.ready = function( fn ) {
+
+ readyList
+ .then( fn )
+
+ // Wrap jQuery.readyException in a function so that the lookup
+ // happens at the time of error handling instead of callback
+ // registration.
+ .catch( function( error ) {
+ jQuery.readyException( error );
+ } );
+
+ return this;
+};
+
+jQuery.extend( {
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+ }
+} );
+
+jQuery.ready.then = readyList.then;
+
+// The ready event handler and self cleanup method
+function completed() {
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+ jQuery.ready();
+}
+
+// Catch cases where $(document).ready() is called
+// after the browser event has already occurred.
+// Support: IE <=9 - 10 only
+// Older IE sometimes signals "interactive" too soon
+if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
+
+} else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+}
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( toType( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ access( elems, fn, i, key[ i ], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, _key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < len; i++ ) {
+ fn(
+ elems[ i ], key, raw ?
+ value :
+ value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
+ }
+ }
+
+ if ( chainable ) {
+ return elems;
+ }
+
+ // Gets
+ if ( bulk ) {
+ return fn.call( elems );
+ }
+
+ return len ? fn( elems[ 0 ], key ) : emptyGet;
+};
+
+
+// Matches dashed string for camelizing
+var rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([a-z])/g;
+
+// Used by camelCase as callback to replace()
+function fcamelCase( _all, letter ) {
+ return letter.toUpperCase();
+}
+
+// Convert dashed to camelCase; used by the css and data modules
+// Support: IE <=9 - 11, Edge 12 - 15
+// Microsoft forgot to hump their vendor prefix (#9572)
+function camelCase( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+}
+var acceptData = function( owner ) {
+
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+
+
+function Data() {
+ this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+
+Data.prototype = {
+
+ cache: function( owner ) {
+
+ // Check if the owner object already has a cache
+ var value = owner[ this.expando ];
+
+ // If not, create one
+ if ( !value ) {
+ value = {};
+
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( acceptData( owner ) ) {
+
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
+
+ // Otherwise secure it in a non-enumerable property
+ // configurable must be true to allow the property to be
+ // deleted when data is removed
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ configurable: true
+ } );
+ }
+ }
+ }
+
+ return value;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ cache = this.cache( owner );
+
+ // Handle: [ owner, key, value ] args
+ // Always use camelCase key (gh-2257)
+ if ( typeof data === "string" ) {
+ cache[ camelCase( data ) ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+
+ // Copy the properties one-by-one to the cache object
+ for ( prop in data ) {
+ cache[ camelCase( prop ) ] = data[ prop ];
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ return key === undefined ?
+ this.cache( owner ) :
+
+ // Always use camelCase key (gh-2257)
+ owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
+ },
+ access: function( owner, key, value ) {
+
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ( ( key && typeof key === "string" ) && value === undefined ) ) {
+
+ return this.get( owner, key );
+ }
+
+ // When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
+
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i,
+ cache = owner[ this.expando ];
+
+ if ( cache === undefined ) {
+ return;
+ }
+
+ if ( key !== undefined ) {
+
+ // Support array or space separated string of keys
+ if ( Array.isArray( key ) ) {
+
+ // If key is an array of keys...
+ // We always set camelCase keys, so remove that.
+ key = key.map( camelCase );
+ } else {
+ key = camelCase( key );
+
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ key = key in cache ?
+ [ key ] :
+ ( key.match( rnothtmlwhite ) || [] );
+ }
+
+ i = key.length;
+
+ while ( i-- ) {
+ delete cache[ key[ i ] ];
+ }
+ }
+
+ // Remove the expando if there's no more data
+ if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
+
+ // Support: Chrome <=35 - 45
+ // Webkit & Blink performance suffers when deleting properties
+ // from DOM nodes, so set to undefined instead
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = undefined;
+ } else {
+ delete owner[ this.expando ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
+ }
+};
+var dataPriv = new Data();
+
+var dataUser = new Data();
+
+
+
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /[A-Z]/g;
+
+function getData( data ) {
+ if ( data === "true" ) {
+ return true;
+ }
+
+ if ( data === "false" ) {
+ return false;
+ }
+
+ if ( data === "null" ) {
+ return null;
+ }
+
+ // Only convert to a number if it doesn't change the string
+ if ( data === +data + "" ) {
+ return +data;
+ }
+
+ if ( rbrace.test( data ) ) {
+ return JSON.parse( data );
+ }
+
+ return data;
+}
+
+function dataAttr( elem, key, data ) {
+ var name;
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = getData( data );
+ } catch ( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ dataUser.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+}
+
+jQuery.extend( {
+ hasData: function( elem ) {
+ return dataUser.hasData( elem ) || dataPriv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return dataUser.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ dataUser.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to dataPriv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return dataPriv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ dataPriv.remove( elem, name );
+ }
+} );
+
+jQuery.fn.extend( {
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = dataUser.get( elem );
+
+ if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE 11 only
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = camelCase( name.slice( 5 ) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ dataPriv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each( function() {
+ dataUser.set( this, key );
+ } );
+ }
+
+ return access( this, function( value ) {
+ var data;
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+
+ // Attempt to get data from the cache
+ // The key will always be camelCased in Data
+ data = dataUser.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
+
+ // Set the data...
+ this.each( function() {
+
+ // We always store the camelCased key
+ dataUser.set( this, key, value );
+ } );
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each( function() {
+ dataUser.remove( this, key );
+ } );
+ }
+} );
+
+
+jQuery.extend( {
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = dataPriv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || Array.isArray( data ) ) {
+ queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // Clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // Not public - generate a queueHooks object, or return the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ dataPriv.remove( elem, [ type + "queue", key ] );
+ } )
+ } );
+ }
+} );
+
+jQuery.fn.extend( {
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[ 0 ], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each( function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // Ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ dequeue: function( type ) {
+ return this.each( function() {
+ jQuery.dequeue( this, type );
+ } );
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+} );
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var documentElement = document.documentElement;
+
+
+
+ var isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem );
+ },
+ composed = { composed: true };
+
+ // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
+ // Check attachment across shadow DOM boundaries when possible (gh-3504)
+ // Support: iOS 10.0-10.2 only
+ // Early iOS 10 versions support `attachShadow` but not `getRootNode`,
+ // leading to errors. We need to check for `getRootNode`.
+ if ( documentElement.getRootNode ) {
+ isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem ) ||
+ elem.getRootNode( composed ) === elem.ownerDocument;
+ };
+ }
+var isHiddenWithinTree = function( elem, el ) {
+
+ // isHiddenWithinTree might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+
+ // Inline style trumps all
+ return elem.style.display === "none" ||
+ elem.style.display === "" &&
+
+ // Otherwise, check computed style
+ // Support: Firefox <=43 - 45
+ // Disconnected elements can have computed display: none, so first confirm that elem is
+ // in the document.
+ isAttached( elem ) &&
+
+ jQuery.css( elem, "display" ) === "none";
+ };
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted, scale,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() {
+ return tween.cur();
+ } :
+ function() {
+ return jQuery.css( elem, prop, "" );
+ },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = elem.nodeType &&
+ ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Support: Firefox <=54
+ // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
+ initial = initial / 2;
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ while ( maxIterations-- ) {
+
+ // Evaluate and update our best guess (doubling guesses that zero out).
+ // Finish if the scale equals or crosses 1 (making the old*new product non-positive).
+ jQuery.style( elem, prop, initialInUnit + unit );
+ if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
+ maxIterations = 0;
+ }
+ initialInUnit = initialInUnit / scale;
+
+ }
+
+ initialInUnit = initialInUnit * 2;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+}
+
+
+var defaultDisplayMap = {};
+
+function getDefaultDisplay( elem ) {
+ var temp,
+ doc = elem.ownerDocument,
+ nodeName = elem.nodeName,
+ display = defaultDisplayMap[ nodeName ];
+
+ if ( display ) {
+ return display;
+ }
+
+ temp = doc.body.appendChild( doc.createElement( nodeName ) );
+ display = jQuery.css( temp, "display" );
+
+ temp.parentNode.removeChild( temp );
+
+ if ( display === "none" ) {
+ display = "block";
+ }
+ defaultDisplayMap[ nodeName ] = display;
+
+ return display;
+}
+
+function showHide( elements, show ) {
+ var display, elem,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ // Determine new display value for elements that need to change
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ display = elem.style.display;
+ if ( show ) {
+
+ // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
+ // check is required in this first loop unless we have a nonempty display value (either
+ // inline or about-to-be-restored)
+ if ( display === "none" ) {
+ values[ index ] = dataPriv.get( elem, "display" ) || null;
+ if ( !values[ index ] ) {
+ elem.style.display = "";
+ }
+ }
+ if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
+ values[ index ] = getDefaultDisplay( elem );
+ }
+ } else {
+ if ( display !== "none" ) {
+ values[ index ] = "none";
+
+ // Remember what we're overwriting
+ dataPriv.set( elem, "display", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop to avoid constant reflow
+ for ( index = 0; index < length; index++ ) {
+ if ( values[ index ] != null ) {
+ elements[ index ].style.display = values[ index ];
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend( {
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each( function() {
+ if ( isHiddenWithinTree( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ } );
+ }
+} );
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
+
+var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
+
+
+
+( function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Android 4.0 - 4.3 only
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Android <=4.1 only
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE <=11 only
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // Support: IE <=9 only
+ // IE <=9 replaces <option> tags with their contents when inserted outside of
+ // the select element.
+ div.innerHTML = "<option></option>";
+ support.option = !!div.lastChild;
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
+
+ // XHTML parsers do not magically insert elements in the
+ // same way that tag soup parsers do. So we cannot shorten
+ // this by omitting <tbody> or other required elements.
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ _default: [ 0, "", "" ]
+};
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: IE <=9 only
+if ( !support.option ) {
+ wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
+}
+
+
+function getAll( context, tag ) {
+
+ // Support: IE <=9 - 11 only
+ // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+ var ret;
+
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ ret = context.getElementsByTagName( tag || "*" );
+
+ } else if ( typeof context.querySelectorAll !== "undefined" ) {
+ ret = context.querySelectorAll( tag || "*" );
+
+ } else {
+ ret = [];
+ }
+
+ if ( tag === undefined || tag && nodeName( context, tag ) ) {
+ return jQuery.merge( [ context ], ret );
+ }
+
+ return ret;
+}
+
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ dataPriv.set(
+ elems[ i ],
+ "globalEval",
+ !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+
+var rhtml = /<|&#?\w+;/;
+
+function buildFragment( elems, context, scripts, selection, ignored ) {
+ var elem, tmp, tag, wrap, attached, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( toType( elem ) === "object" ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
+
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+ continue;
+ }
+
+ attached = isAttached( elem );
+
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( attached ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( ( elem = tmp[ j++ ] ) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ return fragment;
+}
+
+
+var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+// Support: IE <=9 - 11+
+// focus() and blur() are asynchronous, except when they are no-op.
+// So expect focus to be synchronous when the element is already active,
+// and blur to be synchronous when the element is not already active.
+// (focus and blur are always synchronous in other supported browsers,
+// this just defines when we can count on it).
+function expectSync( elem, type ) {
+ return ( elem === safeActiveElement() ) === ( type === "focus" );
+}
+
+// Support: IE <=9 only
+// Accessing document.activeElement can throw unexpectedly
+// https://bugs.jquery.com/ticket/13393
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+function on( elem, types, selector, data, fn, one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ if ( data == null && fn == null ) {
+
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return elem;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.get( elem );
+
+ // Only attach events to objects that accept data
+ if ( !acceptData( elem ) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Ensure that invalid selectors throw exceptions at attach time
+ // Evaluate against documentElement in case elem is a non-element node (e.g., document)
+ if ( selector ) {
+ jQuery.find.matchesSelector( documentElement, selector );
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !( events = elemData.events ) ) {
+ events = elemData.events = Object.create( null );
+ }
+ if ( !( eventHandle = elemData.handle ) ) {
+ eventHandle = elemData.handle = function( e ) {
+
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+ };
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend( {
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join( "." )
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !( handlers = events[ type ] ) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup ||
+ special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[ 2 ] &&
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector ||
+ selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown ||
+ special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove data and the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ dataPriv.remove( elem, "handle events" );
+ }
+ },
+
+ dispatch: function( nativeEvent ) {
+
+ var i, j, ret, matched, handleObj, handlerQueue,
+ args = new Array( arguments.length ),
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( nativeEvent ),
+
+ handlers = (
+ dataPriv.get( this, "events" ) || Object.create( null )
+ )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[ 0 ] = event;
+
+ for ( i = 1; i < arguments.length; i++ ) {
+ args[ i ] = arguments[ i ];
+ }
+
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( ( handleObj = matched.handlers[ j++ ] ) &&
+ !event.isImmediatePropagationStopped() ) {
+
+ // If the event is namespaced, then each handler is only invoked if it is
+ // specially universal or its namespaces are a superset of the event's.
+ if ( !event.rnamespace || handleObj.namespace === false ||
+ event.rnamespace.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+ handleObj.handler ).apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( ( event.result = ret ) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, handleObj, sel, matchedHandlers, matchedSelectors,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ if ( delegateCount &&
+
+ // Support: IE <=9
+ // Black-hole SVG <use> instance trees (trac-13180)
+ cur.nodeType &&
+
+ // Support: Firefox <=42
+ // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
+ // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
+ // Support: IE 11 only
+ // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
+ !( event.type === "click" && event.button >= 1 ) ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
+ matchedHandlers = [];
+ matchedSelectors = {};
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matchedSelectors[ sel ] === undefined ) {
+ matchedSelectors[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) > -1 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matchedSelectors[ sel ] ) {
+ matchedHandlers.push( handleObj );
+ }
+ }
+ if ( matchedHandlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ cur = this;
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
+ }
+
+ return handlerQueue;
+ },
+
+ addProp: function( name, hook ) {
+ Object.defineProperty( jQuery.Event.prototype, name, {
+ enumerable: true,
+ configurable: true,
+
+ get: isFunction( hook ) ?
+ function() {
+ if ( this.originalEvent ) {
+ return hook( this.originalEvent );
+ }
+ } :
+ function() {
+ if ( this.originalEvent ) {
+ return this.originalEvent[ name ];
+ }
+ },
+
+ set: function( value ) {
+ Object.defineProperty( this, name, {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: value
+ } );
+ }
+ } );
+ },
+
+ fix: function( originalEvent ) {
+ return originalEvent[ jQuery.expando ] ?
+ originalEvent :
+ new jQuery.Event( originalEvent );
+ },
+
+ special: {
+ load: {
+
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ click: {
+
+ // Utilize native event to ensure correct state for checkable inputs
+ setup: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Claim the first handler
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ // dataPriv.set( el, "click", ... )
+ leverageNative( el, "click", returnTrue );
+ }
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Force setup before triggering a click
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ leverageNative( el, "click" );
+ }
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ // For cross-browser consistency, suppress native .click() on links
+ // Also prevent it if we're currently inside a leveraged native-event stack
+ _default: function( event ) {
+ var target = event.target;
+ return rcheckableType.test( target.type ) &&
+ target.click && nodeName( target, "input" ) &&
+ dataPriv.get( target, "click" ) ||
+ nodeName( target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ }
+};
+
+// Ensure the presence of an event listener that handles manually-triggered
+// synthetic events by interrupting progress until reinvoked in response to
+// *native* events that it fires directly, ensuring that state changes have
+// already occurred before other listeners are invoked.
+function leverageNative( el, type, expectSync ) {
+
+ // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
+ if ( !expectSync ) {
+ if ( dataPriv.get( el, type ) === undefined ) {
+ jQuery.event.add( el, type, returnTrue );
+ }
+ return;
+ }
+
+ // Register the controller as a special universal handler for all event namespaces
+ dataPriv.set( el, type, false );
+ jQuery.event.add( el, type, {
+ namespace: false,
+ handler: function( event ) {
+ var notAsync, result,
+ saved = dataPriv.get( this, type );
+
+ if ( ( event.isTrigger & 1 ) && this[ type ] ) {
+
+ // Interrupt processing of the outer synthetic .trigger()ed event
+ // Saved data should be false in such cases, but might be a leftover capture object
+ // from an async native handler (gh-4350)
+ if ( !saved.length ) {
+
+ // Store arguments for use when handling the inner native event
+ // There will always be at least one argument (an event object), so this array
+ // will not be confused with a leftover capture object.
+ saved = slice.call( arguments );
+ dataPriv.set( this, type, saved );
+
+ // Trigger the native event and capture its result
+ // Support: IE <=9 - 11+
+ // focus() and blur() are asynchronous
+ notAsync = expectSync( this, type );
+ this[ type ]();
+ result = dataPriv.get( this, type );
+ if ( saved !== result || notAsync ) {
+ dataPriv.set( this, type, false );
+ } else {
+ result = {};
+ }
+ if ( saved !== result ) {
+
+ // Cancel the outer synthetic event
+ event.stopImmediatePropagation();
+ event.preventDefault();
+
+ // Support: Chrome 86+
+ // In Chrome, if an element having a focusout handler is blurred by
+ // clicking outside of it, it invokes the handler synchronously. If
+ // that handler calls `.remove()` on the element, the data is cleared,
+ // leaving `result` undefined. We need to guard against this.
+ return result && result.value;
+ }
+
+ // If this is an inner synthetic event for an event with a bubbling surrogate
+ // (focus or blur), assume that the surrogate already propagated from triggering the
+ // native event and prevent that from happening again here.
+ // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
+ // bubbling surrogate propagates *after* the non-bubbling base), but that seems
+ // less bad than duplication.
+ } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
+ event.stopPropagation();
+ }
+
+ // If this is a native event triggered above, everything is now in order
+ // Fire an inner synthetic event with the original arguments
+ } else if ( saved.length ) {
+
+ // ...and capture the result
+ dataPriv.set( this, type, {
+ value: jQuery.event.trigger(
+
+ // Support: IE <=9 - 11+
+ // Extend with the prototype to reset the above stopImmediatePropagation()
+ jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
+ saved.slice( 1 ),
+ this
+ )
+ } );
+
+ // Abort handling of the native event
+ event.stopImmediatePropagation();
+ }
+ }
+ } );
+}
+
+jQuery.removeEvent = function( elem, type, handle ) {
+
+ // This "if" is needed for plain objects
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle );
+ }
+};
+
+jQuery.Event = function( src, props ) {
+
+ // Allow instantiation without the 'new' keyword
+ if ( !( this instanceof jQuery.Event ) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+
+ // Support: Android <=2.3 only
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Create target properties
+ // Support: Safari <=6 - 7 only
+ // Target should not be a text node (#504, #13143)
+ this.target = ( src.target && src.target.nodeType === 3 ) ?
+ src.target.parentNode :
+ src.target;
+
+ this.currentTarget = src.currentTarget;
+ this.relatedTarget = src.relatedTarget;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || Date.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ constructor: jQuery.Event,
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+ isSimulated: false,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Includes all common event props including KeyEvent and MouseEvent specific props
+jQuery.each( {
+ altKey: true,
+ bubbles: true,
+ cancelable: true,
+ changedTouches: true,
+ ctrlKey: true,
+ detail: true,
+ eventPhase: true,
+ metaKey: true,
+ pageX: true,
+ pageY: true,
+ shiftKey: true,
+ view: true,
+ "char": true,
+ code: true,
+ charCode: true,
+ key: true,
+ keyCode: true,
+ button: true,
+ buttons: true,
+ clientX: true,
+ clientY: true,
+ offsetX: true,
+ offsetY: true,
+ pointerId: true,
+ pointerType: true,
+ screenX: true,
+ screenY: true,
+ targetTouches: true,
+ toElement: true,
+ touches: true,
+ which: true
+}, jQuery.event.addProp );
+
+jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
+ jQuery.event.special[ type ] = {
+
+ // Utilize native event if possible so blur/focus sequence is correct
+ setup: function() {
+
+ // Claim the first handler
+ // dataPriv.set( this, "focus", ... )
+ // dataPriv.set( this, "blur", ... )
+ leverageNative( this, type, expectSync );
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function() {
+
+ // Force setup before trigger
+ leverageNative( this, type );
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ // Suppress native focus or blur as it's already being fired
+ // in leverageNative.
+ _default: function() {
+ return true;
+ },
+
+ delegateType: delegateType
+ };
+} );
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// so that event delegation works in jQuery.
+// Do the same for pointerenter/pointerleave and pointerover/pointerout
+//
+// Support: Safari 7 only
+// Safari sends mouseenter too often; see:
+// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
+// for the description of the bug (it existed in older Chrome versions as well).
+jQuery.each( {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mouseenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+} );
+
+jQuery.fn.extend( {
+
+ on: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn );
+ },
+ one: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ?
+ handleObj.origType + "." + handleObj.namespace :
+ handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each( function() {
+ jQuery.event.remove( this, types, fn, selector );
+ } );
+ }
+} );
+
+
+var
+
+ // Support: IE <=10 - 11, Edge 12 - 13 only
+ // In IE/Edge using regex groups here causes severe slowdowns.
+ // See https://connect.microsoft.com/IE/feedback/details/1736512/
+ rnoInnerhtml = /<script|<style|<link/i,
+
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+
+// Prefer a tbody over its parent table for containing new rows
+function manipulationTarget( elem, content ) {
+ if ( nodeName( elem, "table" ) &&
+ nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
+
+ return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
+ }
+
+ return elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
+ elem.type = elem.type.slice( 5 );
+ } else {
+ elem.removeAttribute( "type" );
+ }
+
+ return elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, udataOld, udataCur, events;
+
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // 1. Copy private data: events, handlers, etc.
+ if ( dataPriv.hasData( src ) ) {
+ pdataOld = dataPriv.get( src );
+ events = pdataOld.events;
+
+ if ( events ) {
+ dataPriv.remove( dest, "handle events" );
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+ }
+
+ // 2. Copy user data
+ if ( dataUser.hasData( src ) ) {
+ udataOld = dataUser.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ dataUser.set( dest, udataCur );
+ }
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
+
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+function domManip( collection, args, callback, ignored ) {
+
+ // Flatten any nested arrays
+ args = flat( args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = collection.length,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ valueIsFunction = isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( valueIsFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return collection.each( function( index ) {
+ var self = collection.eq( index );
+ if ( valueIsFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ domManip( self, args, callback, ignored );
+ } );
+ }
+
+ if ( l ) {
+ fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ // Require either new content or an interest in ignored elements to invoke the callback
+ if ( first || ignored ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item
+ // instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( collection[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !dataPriv.access( node, "globalEval" ) &&
+ jQuery.contains( doc, node ) ) {
+
+ if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
+
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl && !node.noModule ) {
+ jQuery._evalUrl( node.src, {
+ nonce: node.nonce || node.getAttribute( "nonce" )
+ }, doc );
+ }
+ } else {
+ DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return collection;
+}
+
+function remove( elem, selector, keepData ) {
+ var node,
+ nodes = selector ? jQuery.filter( selector, elem ) : elem,
+ i = 0;
+
+ for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+ if ( !keepData && node.nodeType === 1 ) {
+ jQuery.cleanData( getAll( node ) );
+ }
+
+ if ( node.parentNode ) {
+ if ( keepData && isAttached( node ) ) {
+ setGlobalEval( getAll( node, "script" ) );
+ }
+ node.parentNode.removeChild( node );
+ }
+ }
+
+ return elem;
+}
+
+jQuery.extend( {
+ htmlPrefilter: function( html ) {
+ return html;
+ },
+
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = isAttached( elem );
+
+ // Fix IE cloning issues
+ if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+ !jQuery.isXMLDoc( elem ) ) {
+
+ // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ // Return the cloned set
+ return clone;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, type,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+ if ( acceptData( elem ) ) {
+ if ( ( data = elem[ dataPriv.expando ] ) ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataPriv.expando ] = undefined;
+ }
+ if ( elem[ dataUser.expando ] ) {
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataUser.expando ] = undefined;
+ }
+ }
+ }
+ }
+} );
+
+jQuery.fn.extend( {
+ detach: function( selector ) {
+ return remove( this, selector, true );
+ },
+
+ remove: function( selector ) {
+ return remove( this, selector );
+ },
+
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().each( function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ } );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ } );
+ },
+
+ prepend: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ } );
+ },
+
+ before: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ } );
+ },
+
+ after: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ } );
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; ( elem = this[ i ] ) != null; i++ ) {
+ if ( elem.nodeType === 1 ) {
+
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
+
+ // Remove any remaining nodes
+ elem.textContent = "";
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ } );
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+ value = jQuery.htmlPrefilter( value );
+
+ try {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch ( e ) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var ignored = [];
+
+ // Make the changes, replacing each non-ignored context element with the new content
+ return domManip( this, arguments, function( elem ) {
+ var parent = this.parentNode;
+
+ if ( jQuery.inArray( this, ignored ) < 0 ) {
+ jQuery.cleanData( getAll( this ) );
+ if ( parent ) {
+ parent.replaceChild( elem, this );
+ }
+ }
+
+ // Force callback invocation
+ }, ignored );
+ }
+} );
+
+jQuery.each( {
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1,
+ i = 0;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // .get() because push.apply(_, arraylike) throws on ancient WebKit
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+} );
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+
+ // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ var view = elem.ownerDocument.defaultView;
+
+ if ( !view || !view.opener ) {
+ view = window;
+ }
+
+ return view.getComputedStyle( elem );
+ };
+
+var swap = function( elem, options, callback ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
+
+
+
+( function() {
+
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computeStyleTests() {
+
+ // This is a singleton, we need to execute it only once
+ if ( !div ) {
+ return;
+ }
+
+ container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
+ "margin-top:1px;padding:0;border:0";
+ div.style.cssText =
+ "position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
+ "margin:auto;border:1px;padding:1px;" +
+ "width:60%;top:1%";
+ documentElement.appendChild( container ).appendChild( div );
+
+ var divStyle = window.getComputedStyle( div );
+ pixelPositionVal = divStyle.top !== "1%";
+
+ // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
+ reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
+
+ // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
+ // Some styles come back with percentage values, even though they shouldn't
+ div.style.right = "60%";
+ pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
+
+ // Support: IE 9 - 11 only
+ // Detect misreporting of content dimensions for box-sizing:border-box elements
+ boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
+
+ // Support: IE 9 only
+ // Detect overflow:scroll screwiness (gh-3699)
+ // Support: Chrome <=64
+ // Don't get tricked when zoom affects offsetWidth (gh-4029)
+ div.style.position = "absolute";
+ scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
+
+ documentElement.removeChild( container );
+
+ // Nullify the div so it wouldn't be stored in the memory and
+ // it will also be a sign that checks already performed
+ div = null;
+ }
+
+ function roundPixelMeasures( measure ) {
+ return Math.round( parseFloat( measure ) );
+ }
+
+ var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
+ reliableTrDimensionsVal, reliableMarginLeftVal,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
+
+ // Finish early in limited (non-browser) environments
+ if ( !div.style ) {
+ return;
+ }
+
+ // Support: IE <=9 - 11 only
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ jQuery.extend( support, {
+ boxSizingReliable: function() {
+ computeStyleTests();
+ return boxSizingReliableVal;
+ },
+ pixelBoxStyles: function() {
+ computeStyleTests();
+ return pixelBoxStylesVal;
+ },
+ pixelPosition: function() {
+ computeStyleTests();
+ return pixelPositionVal;
+ },
+ reliableMarginLeft: function() {
+ computeStyleTests();
+ return reliableMarginLeftVal;
+ },
+ scrollboxSize: function() {
+ computeStyleTests();
+ return scrollboxSizeVal;
+ },
+
+ // Support: IE 9 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Behavior in IE 9 is more subtle than in newer versions & it passes
+ // some versions of this test; make sure not to make it pass there!
+ //
+ // Support: Firefox 70+
+ // Only Firefox includes border widths
+ // in computed dimensions. (gh-4529)
+ reliableTrDimensions: function() {
+ var table, tr, trChild, trStyle;
+ if ( reliableTrDimensionsVal == null ) {
+ table = document.createElement( "table" );
+ tr = document.createElement( "tr" );
+ trChild = document.createElement( "div" );
+
+ table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
+ tr.style.cssText = "border:1px solid";
+
+ // Support: Chrome 86+
+ // Height set through cssText does not get applied.
+ // Computed height then comes back as 0.
+ tr.style.height = "1px";
+ trChild.style.height = "9px";
+
+ // Support: Android 8 Chrome 86+
+ // In our bodyBackground.html iframe,
+ // display for all div elements is set to "inline",
+ // which causes a problem only in Android 8 Chrome 86.
+ // Ensuring the div is display: block
+ // gets around this issue.
+ trChild.style.display = "block";
+
+ documentElement
+ .appendChild( table )
+ .appendChild( tr )
+ .appendChild( trChild );
+
+ trStyle = window.getComputedStyle( tr );
+ reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +
+ parseInt( trStyle.borderTopWidth, 10 ) +
+ parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;
+
+ documentElement.removeChild( table );
+ }
+ return reliableTrDimensionsVal;
+ }
+ } );
+} )();
+
+
+function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+
+ // Support: Firefox 51+
+ // Retrieving style before computed somehow
+ // fixes an issue with getting wrong values
+ // on detached elements
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is needed for:
+ // .css('filter') (IE 9 only, #12537)
+ // .css('--customProperty) (#3144)
+ if ( computed ) {
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !isAttached( elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Android Browser returns percentage for some values,
+ // but width seems to be reliably pixels.
+ // This is against the CSSOM draft spec:
+ // https://drafts.csswg.org/cssom/#resolved-values
+ if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret !== undefined ?
+
+ // Support: IE <=9 - 11 only
+ // IE returns zIndex value as an integer.
+ ret + "" :
+ ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ if ( conditionFn() ) {
+
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+ return ( this.get = hookFn ).apply( this, arguments );
+ }
+ };
+}
+
+
+var cssPrefixes = [ "Webkit", "Moz", "ms" ],
+ emptyStyle = document.createElement( "div" ).style,
+ vendorProps = {};
+
+// Return a vendor-prefixed property or undefined
+function vendorPropName( name ) {
+
+ // Check for vendor prefixed names
+ var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ }
+}
+
+// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
+function finalPropName( name ) {
+ var final = jQuery.cssProps[ name ] || vendorProps[ name ];
+
+ if ( final ) {
+ return final;
+ }
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ return vendorProps[ name ] = vendorPropName( name ) || name;
+}
+
+
+var
+
+ // Swappable if display is none or starts with table
+ // except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rcustomProp = /^--/,
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ };
+
+function setPositiveNumber( _elem, value, subtract ) {
+
+ // Any relative (+/-) values have already been
+ // normalized at this point
+ var matches = rcssNum.exec( value );
+ return matches ?
+
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
+ value;
+}
+
+function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
+ var i = dimension === "width" ? 1 : 0,
+ extra = 0,
+ delta = 0;
+
+ // Adjustment may not be necessary
+ if ( box === ( isBorderBox ? "border" : "content" ) ) {
+ return 0;
+ }
+
+ for ( ; i < 4; i += 2 ) {
+
+ // Both box models exclude margin
+ if ( box === "margin" ) {
+ delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
+ }
+
+ // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
+ if ( !isBorderBox ) {
+
+ // Add padding
+ delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // For "border" or "margin", add border
+ if ( box !== "padding" ) {
+ delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+
+ // But still keep track of it otherwise
+ } else {
+ extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+
+ // If we get here with a border-box (content + padding + border), we're seeking "content" or
+ // "padding" or "margin"
+ } else {
+
+ // For "content", subtract padding
+ if ( box === "content" ) {
+ delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // For "content" or "padding", subtract border
+ if ( box !== "margin" ) {
+ delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ // Account for positive content-box scroll gutter when requested by providing computedVal
+ if ( !isBorderBox && computedVal >= 0 ) {
+
+ // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
+ // Assuming integer scroll gutter, subtract the rest and round down
+ delta += Math.max( 0, Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ computedVal -
+ delta -
+ extra -
+ 0.5
+
+ // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
+ // Use an explicit zero to avoid NaN (gh-3964)
+ ) ) || 0;
+ }
+
+ return delta;
+}
+
+function getWidthOrHeight( elem, dimension, extra ) {
+
+ // Start with computed style
+ var styles = getStyles( elem ),
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
+ // Fake content-box until we know it's needed to know the true value.
+ boxSizingNeeded = !support.boxSizingReliable() || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ valueIsBorderBox = isBorderBox,
+
+ val = curCSS( elem, dimension, styles ),
+ offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
+
+ // Support: Firefox <=54
+ // Return a confounding non-pixel value or feign ignorance, as appropriate.
+ if ( rnumnonpx.test( val ) ) {
+ if ( !extra ) {
+ return val;
+ }
+ val = "auto";
+ }
+
+
+ // Support: IE 9 - 11 only
+ // Use offsetWidth/offsetHeight for when box sizing is unreliable.
+ // In those cases, the computed value can be trusted to be border-box.
+ if ( ( !support.boxSizingReliable() && isBorderBox ||
+
+ // Support: IE 10 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Interestingly, in some cases IE 9 doesn't suffer from this issue.
+ !support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
+
+ // Fall back to offsetWidth/offsetHeight when value is "auto"
+ // This happens for inline elements with no explicit setting (gh-3571)
+ val === "auto" ||
+
+ // Support: Android <=4.1 - 4.3 only
+ // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
+ !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
+
+ // Make sure the element is visible & connected
+ elem.getClientRects().length ) {
+
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // Where available, offsetWidth/offsetHeight approximate border box dimensions.
+ // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
+ // retrieved value as a content box dimension.
+ valueIsBorderBox = offsetProp in elem;
+ if ( valueIsBorderBox ) {
+ val = elem[ offsetProp ];
+ }
+ }
+
+ // Normalize "" and auto
+ val = parseFloat( val ) || 0;
+
+ // Adjust for the element's box model
+ return ( val +
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles,
+
+ // Provide the current computed size to request scroll gutter calculation (gh-3589)
+ val
+ )
+ ) + "px";
+}
+
+jQuery.extend( {
+
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "animationIterationCount": true,
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "gridArea": true,
+ "gridColumn": true,
+ "gridColumnEnd": true,
+ "gridColumnStart": true,
+ "gridRow": true,
+ "gridRowEnd": true,
+ "gridRowStart": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {},
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name ),
+ style = elem.style;
+
+ // Make sure that we're working with the right name. We don't
+ // want to query the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Gets hook for the prefixed version, then unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
+
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set (#7116)
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
+ // "px" to a few hardcoded values.
+ if ( type === "number" && !isCustomProp ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
+ }
+
+ // background-* props affect original clone's values
+ if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !( "set" in hooks ) ||
+ ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
+
+ if ( isCustomProp ) {
+ style.setProperty( name, value );
+ } else {
+ style[ name ] = value;
+ }
+ }
+
+ } else {
+
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks &&
+ ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
+
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name );
+
+ // Make sure that we're working with the right name. We don't
+ // want to modify the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Try prefixed name followed by the unprefixed name
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ // Convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Make numeric if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || isFinite( num ) ? num || 0 : val;
+ }
+
+ return val;
+ }
+} );
+
+jQuery.each( [ "height", "width" ], function( _i, dimension ) {
+ jQuery.cssHooks[ dimension ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+
+ // Support: Safari 8+
+ // Table columns in Safari have non-zero offsetWidth & zero
+ // getBoundingClientRect().width unless display is changed.
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a disconnected node
+ // in IE throws an error.
+ ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
+ swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, dimension, extra );
+ } ) :
+ getWidthOrHeight( elem, dimension, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var matches,
+ styles = getStyles( elem ),
+
+ // Only read styles.position if the test has a chance to fail
+ // to avoid forcing a reflow.
+ scrollboxSizeBuggy = !support.scrollboxSize() &&
+ styles.position === "absolute",
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
+ boxSizingNeeded = scrollboxSizeBuggy || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ subtract = extra ?
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra,
+ isBorderBox,
+ styles
+ ) :
+ 0;
+
+ // Account for unreliable border-box dimensions by comparing offset* to computed and
+ // faking a content-box to get border and padding (gh-3699)
+ if ( isBorderBox && scrollboxSizeBuggy ) {
+ subtract -= Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ parseFloat( styles[ dimension ] ) -
+ boxModelAdjustment( elem, dimension, "border", false, styles ) -
+ 0.5
+ );
+ }
+
+ // Convert to pixels if value adjustment is needed
+ if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+ ( matches[ 3 ] || "px" ) !== "px" ) {
+
+ elem.style[ dimension ] = value;
+ value = jQuery.css( elem, dimension );
+ }
+
+ return setPositiveNumber( elem, value, subtract );
+ }
+ };
+} );
+
+jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
+ function( elem, computed ) {
+ if ( computed ) {
+ return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+ elem.getBoundingClientRect().left -
+ swap( elem, { marginLeft: 0 }, function() {
+ return elem.getBoundingClientRect().left;
+ } )
+ ) + "px";
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each( {
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // Assumes a single number if not a string
+ parts = typeof value === "string" ? value.split( " " ) : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( prefix !== "margin" ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+} );
+
+jQuery.fn.extend( {
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( Array.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ }
+} );
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || jQuery.easing._default;
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ // Use a property on the element directly when it is not a DOM element,
+ // or when there is no matching style property that exists.
+ if ( tween.elem.nodeType !== 1 ||
+ tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.nodeType === 1 && (
+ jQuery.cssHooks[ tween.prop ] ||
+ tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9 only
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ },
+ _default: "swing"
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, inProgress,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rrun = /queueHooks$/;
+
+function schedule() {
+ if ( inProgress ) {
+ if ( document.hidden === false && window.requestAnimationFrame ) {
+ window.requestAnimationFrame( schedule );
+ } else {
+ window.setTimeout( schedule, jQuery.fx.interval );
+ }
+
+ jQuery.fx.tick();
+ }
+}
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ window.setTimeout( function() {
+ fxNow = undefined;
+ } );
+ return ( fxNow = Date.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ i = 0,
+ attrs = { height: type };
+
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
+
+ // We're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+ isBox = "width" in props || "height" in props,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHiddenWithinTree( elem ),
+ dataShow = dataPriv.get( elem, "fxshow" );
+
+ // Queue-skipping animations hijack the fx hooks
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always( function() {
+
+ // Ensure the complete handler is called before this completes
+ anim.always( function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ } );
+ } );
+ }
+
+ // Detect show/hide animations
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.test( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // Pretend to be hidden if this is a "show" and
+ // there is still data from a stopped show/hide
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+
+ // Ignore all other no-op show/hide data
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ // Bail out if this is a no-op like .hide().hide()
+ propTween = !jQuery.isEmptyObject( props );
+ if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+ return;
+ }
+
+ // Restrict "overflow" and "display" styles during box animations
+ if ( isBox && elem.nodeType === 1 ) {
+
+ // Support: IE <=9 - 11, Edge 12 - 15
+ // Record all 3 overflow attributes because IE does not infer the shorthand
+ // from identically-valued overflowX and overflowY and Edge just mirrors
+ // the overflowX value there.
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Identify a display type, preferring old show/hide data over the CSS cascade
+ restoreDisplay = dataShow && dataShow.display;
+ if ( restoreDisplay == null ) {
+ restoreDisplay = dataPriv.get( elem, "display" );
+ }
+ display = jQuery.css( elem, "display" );
+ if ( display === "none" ) {
+ if ( restoreDisplay ) {
+ display = restoreDisplay;
+ } else {
+
+ // Get nonempty value(s) by temporarily forcing visibility
+ showHide( [ elem ], true );
+ restoreDisplay = elem.style.display || restoreDisplay;
+ display = jQuery.css( elem, "display" );
+ showHide( [ elem ] );
+ }
+ }
+
+ // Animate inline elements as inline-block
+ if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+ if ( jQuery.css( elem, "float" ) === "none" ) {
+
+ // Restore the original display value at the end of pure show/hide animations
+ if ( !propTween ) {
+ anim.done( function() {
+ style.display = restoreDisplay;
+ } );
+ if ( restoreDisplay == null ) {
+ display = style.display;
+ restoreDisplay = display === "none" ? "" : display;
+ }
+ }
+ style.display = "inline-block";
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always( function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ } );
+ }
+
+ // Implement show/hide animations
+ propTween = false;
+ for ( prop in orig ) {
+
+ // General show/hide setup for this element animation
+ if ( !propTween ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
+ }
+
+ // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+
+ // Show elements before animating them
+ if ( hidden ) {
+ showHide( [ elem ], true );
+ }
+
+ /* eslint-disable no-loop-func */
+
+ anim.done( function() {
+
+ /* eslint-enable no-loop-func */
+
+ // The final step of a "hide" animation is actually hiding the element
+ if ( !hidden ) {
+ showHide( [ elem ] );
+ }
+ dataPriv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ } );
+ }
+
+ // Per-property setup
+ propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = propTween.start;
+ if ( hidden ) {
+ propTween.end = propTween.start;
+ propTween.start = 0;
+ }
+ }
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( Array.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = Animation.prefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+
+ // Don't match elem in the :animated selector
+ delete tick.elem;
+ } ),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+
+ // Support: Android 2.3 only
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ] );
+
+ // If there's more to do, yield
+ if ( percent < 1 && length ) {
+ return remaining;
+ }
+
+ // If this was an empty animation, synthesize a final progress notification
+ if ( !length ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ }
+
+ // Resolve the animation and report its conclusion
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ },
+ animation = deferred.promise( {
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, {
+ specialEasing: {},
+ easing: jQuery.easing._default
+ }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+
+ // If we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // Resolve when we played the last frame; otherwise, reject
+ if ( gotoEnd ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ } ),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length; index++ ) {
+ result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ if ( isFunction( result.stop ) ) {
+ jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+ result.stop.bind( result );
+ }
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ // Attach callbacks from options
+ animation
+ .progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ } )
+ );
+
+ return animation;
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweeners: {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+ return tween;
+ } ]
+ },
+
+ tweener: function( props, callback ) {
+ if ( isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.match( rnothtmlwhite );
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length; index++ ) {
+ prop = props[ index ];
+ Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+ Animation.tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilters: [ defaultPrefilter ],
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ Animation.prefilters.unshift( callback );
+ } else {
+ Animation.prefilters.push( callback );
+ }
+ }
+} );
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !isFunction( easing ) && easing
+ };
+
+ // Go to the end state if fx are off
+ if ( jQuery.fx.off ) {
+ opt.duration = 0;
+
+ } else {
+ if ( typeof opt.duration !== "number" ) {
+ if ( opt.duration in jQuery.fx.speeds ) {
+ opt.duration = jQuery.fx.speeds[ opt.duration ];
+
+ } else {
+ opt.duration = jQuery.fx.speeds._default;
+ }
+ }
+ }
+
+ // Normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend( {
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // Show any hidden elements after setting opacity to 0
+ return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
+
+ // Animate to the value specified
+ .end().animate( { opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || dataPriv.get( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each( function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = dataPriv.get( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this &&
+ ( type == null || timers[ index ].queue === type ) ) {
+
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each( function() {
+ var index,
+ data = dataPriv.get( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // Enable finishing flag on private data
+ data.finish = true;
+
+ // Empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // Look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // Turn off finishing flag
+ delete data.finish;
+ } );
+ }
+} );
+
+jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+} );
+
+// Generate shortcuts for custom animations
+jQuery.each( {
+ slideDown: genFx( "show" ),
+ slideUp: genFx( "hide" ),
+ slideToggle: genFx( "toggle" ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+} );
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ i = 0,
+ timers = jQuery.timers;
+
+ fxNow = Date.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+
+ // Run the timer and safely remove it when done (allowing for external removal)
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ jQuery.fx.start();
+};
+
+jQuery.fx.interval = 13;
+jQuery.fx.start = function() {
+ if ( inProgress ) {
+ return;
+ }
+
+ inProgress = true;
+ schedule();
+};
+
+jQuery.fx.stop = function() {
+ inProgress = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = window.setTimeout( next, time );
+ hooks.stop = function() {
+ window.clearTimeout( timeout );
+ };
+ } );
+};
+
+
+( function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
+
+ input.type = "checkbox";
+
+ // Support: Android <=4.3 only
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
+
+ // Support: IE <=11 only
+ // Must access selectedIndex to make default options select
+ support.optSelected = opt.selected;
+
+ // Support: IE <=11 only
+ // An input loses its value after becoming a radio
+ input = document.createElement( "input" );
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+} )();
+
+
+var boolHook,
+ attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend( {
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each( function() {
+ jQuery.removeAttr( this, name );
+ } );
+ }
+} );
+
+jQuery.extend( {
+ attr: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set attributes on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // Attribute hooks are determined by the lowercase version
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
+ }
+
+ if ( value !== undefined ) {
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+ }
+
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ? undefined : ret;
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" &&
+ nodeName( elem, "input" ) ) {
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name,
+ i = 0,
+
+ // Attribute names can contain non-HTML whitespace characters
+ // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
+ attrNames = value && value.match( rnothtmlwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( ( name = attrNames[ i++ ] ) ) {
+ elem.removeAttribute( name );
+ }
+ }
+ }
+} );
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ elem.setAttribute( name, name );
+ }
+ return name;
+ }
+};
+
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle,
+ lowercaseName = name.toLowerCase();
+
+ if ( !isXML ) {
+
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ lowercaseName ];
+ attrHandle[ lowercaseName ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ lowercaseName :
+ null;
+ attrHandle[ lowercaseName ] = handle;
+ }
+ return ret;
+ };
+} );
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend( {
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each( function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ } );
+ }
+} );
+
+jQuery.extend( {
+ prop: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ return ( elem[ name ] = value );
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ return elem[ name ];
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+
+ // Support: IE <=9 - 11 only
+ // elem.tabIndex doesn't always return the
+ // correct value when it hasn't been explicitly set
+ // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ if ( tabindex ) {
+ return parseInt( tabindex, 10 );
+ }
+
+ if (
+ rfocusable.test( elem.nodeName ) ||
+ rclickable.test( elem.nodeName ) &&
+ elem.href
+ ) {
+ return 0;
+ }
+
+ return -1;
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ }
+} );
+
+// Support: IE <=11 only
+// Accessing the selectedIndex property
+// forces the browser to respect setting selected
+// on the option
+// The getter ensures a default option is selected
+// when in an optgroup
+// eslint rule "no-unused-expressions" is disabled for this code
+// since it considers such accessions noop
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ },
+ set: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+ };
+}
+
+jQuery.each( [
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+} );
+
+
+
+
+ // Strip and collapse whitespace according to HTML spec
+ // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+ function stripAndCollapse( value ) {
+ var tokens = value.match( rnothtmlwhite ) || [];
+ return tokens.join( " " );
+ }
+
+
+function getClass( elem ) {
+ return elem.getAttribute && elem.getAttribute( "class" ) || "";
+}
+
+function classesToArray( value ) {
+ if ( Array.isArray( value ) ) {
+ return value;
+ }
+ if ( typeof value === "string" ) {
+ return value.match( rnothtmlwhite ) || [];
+ }
+ return [];
+}
+
+jQuery.fn.extend( {
+ addClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ if ( !arguments.length ) {
+ return this.attr( "class", "" );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isValidValue = type === "string" || Array.isArray( value );
+
+ if ( typeof stateVal === "boolean" && isValidValue ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( isFunction( value ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).toggleClass(
+ value.call( this, i, getClass( this ), stateVal ),
+ stateVal
+ );
+ } );
+ }
+
+ return this.each( function() {
+ var className, i, self, classNames;
+
+ if ( isValidValue ) {
+
+ // Toggle individual class names
+ i = 0;
+ self = jQuery( this );
+ classNames = classesToArray( value );
+
+ while ( ( className = classNames[ i++ ] ) ) {
+
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( value === undefined || type === "boolean" ) {
+ className = getClass( this );
+ if ( className ) {
+
+ // Store className if set
+ dataPriv.set( this, "__className__", className );
+ }
+
+ // If the element has a class name or if we're passed `false`,
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ if ( this.setAttribute ) {
+ this.setAttribute( "class",
+ className || value === false ?
+ "" :
+ dataPriv.get( this, "__className__" ) || ""
+ );
+ }
+ }
+ } );
+ },
+
+ hasClass: function( selector ) {
+ var className, elem,
+ i = 0;
+
+ className = " " + selector + " ";
+ while ( ( elem = this[ i++ ] ) ) {
+ if ( elem.nodeType === 1 &&
+ ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+} );
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend( {
+ val: function( value ) {
+ var hooks, ret, valueIsFunction,
+ elem = this[ 0 ];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] ||
+ jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks &&
+ "get" in hooks &&
+ ( ret = hooks.get( elem, "value" ) ) !== undefined
+ ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ // Handle most common string cases
+ if ( typeof ret === "string" ) {
+ return ret.replace( rreturn, "" );
+ }
+
+ // Handle cases where value is null/undef or number
+ return ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ valueIsFunction = isFunction( value );
+
+ return this.each( function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( valueIsFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+
+ } else if ( typeof val === "number" ) {
+ val += "";
+
+ } else if ( Array.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ } );
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ } );
+ }
+} );
+
+jQuery.extend( {
+ valHooks: {
+ option: {
+ get: function( elem ) {
+
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+
+ // Support: IE <=10 - 11 only
+ // option.text throws exceptions (#14686, #14858)
+ // Strip and collapse whitespace
+ // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+ stripAndCollapse( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option, i,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one",
+ values = one ? null : [],
+ max = one ? index + 1 : options.length;
+
+ if ( index < 0 ) {
+ i = max;
+
+ } else {
+ i = one ? index : 0;
+ }
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Support: IE <=9 only
+ // IE8-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+
+ // Don't return options that are disabled or in a disabled optgroup
+ !option.disabled &&
+ ( !option.parentNode.disabled ||
+ !nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ /* eslint-disable no-cond-assign */
+
+ if ( option.selected =
+ jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
+ ) {
+ optionSet = true;
+ }
+
+ /* eslint-enable no-cond-assign */
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+} );
+
+// Radios and checkboxes getter/setter
+jQuery.each( [ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( Array.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+ };
+ }
+} );
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+support.focusin = "onfocusin" in window;
+
+
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ stopPropagationCallback = function( e ) {
+ e.stopPropagation();
+ };
+
+jQuery.extend( jQuery.event, {
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+ cur = lastElement = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "." ) > -1 ) {
+
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split( "." );
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join( "." );
+ event.rnamespace = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === ( elem.ownerDocument || document ) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+ lastElement = cur;
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] &&
+ dataPriv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( ( !special._default ||
+ special._default.apply( eventPath.pop(), data ) === false ) &&
+ acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.addEventListener( type, stopPropagationCallback );
+ }
+
+ elem[ type ]();
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.removeEventListener( type, stopPropagationCallback );
+ }
+
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ // Piggyback on a donor event to simulate a different one
+ // Used only for `focus(in | out)` events
+ simulate: function( type, elem, event ) {
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true
+ }
+ );
+
+ jQuery.event.trigger( e, null, elem );
+ }
+
+} );
+
+jQuery.fn.extend( {
+
+ trigger: function( type, data ) {
+ return this.each( function() {
+ jQuery.event.trigger( type, data, this );
+ } );
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[ 0 ];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+} );
+
+
+// Support: Firefox <=44
+// Firefox doesn't have focus(in | out) events
+// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+//
+// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+// focus(in | out) events fire after focus & blur events,
+// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+if ( !support.focusin ) {
+ jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+
+ // Handle: regular nodes (via `this.ownerDocument`), window
+ // (via `this.document`) & document (via `this`).
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ dataPriv.remove( doc, fix );
+
+ } else {
+ dataPriv.access( doc, fix, attaches );
+ }
+ }
+ };
+ } );
+}
+var location = window.location;
+
+var nonce = { guid: Date.now() };
+
+var rquery = ( /\?/ );
+
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, parserErrorElem;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE throws on parseFromString with invalid input.
+ try {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {}
+
+ parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ];
+ if ( !xml || parserErrorElem ) {
+ jQuery.error( "Invalid XML: " + (
+ parserErrorElem ?
+ jQuery.map( parserErrorElem.childNodes, function( el ) {
+ return el.textContent;
+ } ).join( "\n" ) :
+ data
+ ) );
+ }
+ return xml;
+};
+
+
+var
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( Array.isArray( obj ) ) {
+
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams(
+ prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
+ v,
+ traditional,
+ add
+ );
+ }
+ } );
+
+ } else if ( !traditional && toType( obj ) === "object" ) {
+
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, valueOrFunction ) {
+
+ // If value is a function, invoke it and use its return value
+ var value = isFunction( valueOrFunction ) ?
+ valueOrFunction() :
+ valueOrFunction;
+
+ s[ s.length ] = encodeURIComponent( key ) + "=" +
+ encodeURIComponent( value == null ? "" : value );
+ };
+
+ if ( a == null ) {
+ return "";
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ } );
+
+ } else {
+
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" );
+};
+
+jQuery.fn.extend( {
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map( function() {
+
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ } ).filter( function() {
+ var type = this.type;
+
+ // Use .is( ":disabled" ) so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ } ).map( function( _i, elem ) {
+ var val = jQuery( this ).val();
+
+ if ( val == null ) {
+ return null;
+ }
+
+ if ( Array.isArray( val ) ) {
+ return jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } );
+ }
+
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } ).get();
+ }
+} );
+
+
+var
+ r20 = /%20/g,
+ rhash = /#.*$/,
+ rantiCache = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat( "*" ),
+
+ // Anchor tag for parsing the document origin
+ originAnchor = document.createElement( "a" );
+
+originAnchor.href = location.href;
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
+
+ if ( isFunction( func ) ) {
+
+ // For each dataType in the dataTypeExpression
+ while ( ( dataType = dataTypes[ i++ ] ) ) {
+
+ // Prepend if requested
+ if ( dataType[ 0 ] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
+
+ // Otherwise append
+ } else {
+ ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" &&
+ !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ } );
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s.throws ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return {
+ state: "parsererror",
+ error: conv ? e : "No conversion from " + prev + " to " + current
+ };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend( {
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: location.href,
+ type: "GET",
+ isLocal: rlocalProtocol.test( location.protocol ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /\bxml\b/,
+ html: /\bhtml/,
+ json: /\bjson\b/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": JSON.parse,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+
+ // URL without anti-cache param
+ cacheURL,
+
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+
+ // timeout handle
+ timeoutTimer,
+
+ // Url cleanup var
+ urlAnchor,
+
+ // Request state (becomes false upon send and true upon completion)
+ completed,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ // Loop variable
+ i,
+
+ // uncached part of the url
+ uncached,
+
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+
+ // Callbacks context
+ callbackContext = s.context || s,
+
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context &&
+ ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+
+ // Default abort message
+ strAbort = "canceled",
+
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( completed ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
+ ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
+ .concat( match[ 2 ] );
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() + " " ];
+ }
+ return match == null ? null : match.join( ", " );
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return completed ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( completed == null ) {
+ name = requestHeadersNames[ name.toLowerCase() ] =
+ requestHeadersNames[ name.toLowerCase() ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( completed == null ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( completed ) {
+
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ } else {
+
+ // Lazy-add the new callbacks in a way that preserves old ones
+ for ( code in map ) {
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+
+ // Add protocol if not provided (prefilters might expect it)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || location.href ) + "" )
+ .replace( rprotocol, location.protocol + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
+
+ // A cross-domain request is in order when the origin doesn't match the current origin.
+ if ( s.crossDomain == null ) {
+ urlAnchor = document.createElement( "a" );
+
+ // Support: IE <=8 - 11, Edge 12 - 15
+ // IE throws exception on accessing the href property if url is malformed,
+ // e.g. http://example.com:80x/
+ try {
+ urlAnchor.href = s.url;
+
+ // Support: IE <=8 - 11 only
+ // Anchor's host property isn't correctly set when s.url is relative
+ urlAnchor.href = urlAnchor.href;
+ s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+ urlAnchor.protocol + "//" + urlAnchor.host;
+ } catch ( e ) {
+
+ // If there is an error parsing the URL, assume it is crossDomain,
+ // it can be rejected by the transport if it is invalid
+ s.crossDomain = true;
+ }
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ // Remove hash to simplify url manipulation
+ cacheURL = s.url.replace( rhash, "" );
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // Remember the hash so we can put it back
+ uncached = s.url.slice( cacheURL.length );
+
+ // If data is available and should be processed, append data to url
+ if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
+ cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
+
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add or update anti-cache param if needed
+ if ( s.cache === false ) {
+ cacheURL = cacheURL.replace( rantiCache, "$1" );
+ uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
+ uncached;
+ }
+
+ // Put hash and anti-cache on the URL that will be requested (gh-1732)
+ s.url = cacheURL + uncached;
+
+ // Change '%20' to '+' if this is encoded form body content (gh-2658)
+ } else if ( s.data && s.processData &&
+ ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
+ s.data = s.data.replace( r20, "+" );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+ s.accepts[ s.dataTypes[ 0 ] ] +
+ ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend &&
+ ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
+
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // Aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ completeDeferred.add( s.complete );
+ jqXHR.done( s.success );
+ jqXHR.fail( s.error );
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+
+ // If request was aborted inside ajaxSend, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = window.setTimeout( function() {
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ completed = false;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+
+ // Rethrow post-completion exceptions
+ if ( completed ) {
+ throw e;
+ }
+
+ // Propagate others as results
+ done( -1, e );
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Ignore repeat invocations
+ if ( completed ) {
+ return;
+ }
+
+ completed = true;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ window.clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Use a noop converter for missing script but not if jsonp
+ if ( !isSuccess &&
+ jQuery.inArray( "script", s.dataTypes ) > -1 &&
+ jQuery.inArray( "json", s.dataTypes ) < 0 ) {
+ s.converters[ "text script" ] = function() {};
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader( "Last-Modified" );
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader( "etag" );
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+
+ // Extract error from statusText and normalize for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+} );
+
+jQuery.each( [ "get", "post" ], function( _i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+
+ // Shift arguments if data argument was omitted
+ if ( isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ // The url can be an options object (which then must have .url)
+ return jQuery.ajax( jQuery.extend( {
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ }, jQuery.isPlainObject( url ) && url ) );
+ };
+} );
+
+jQuery.ajaxPrefilter( function( s ) {
+ var i;
+ for ( i in s.headers ) {
+ if ( i.toLowerCase() === "content-type" ) {
+ s.contentType = s.headers[ i ] || "";
+ }
+ }
+} );
+
+
+jQuery._evalUrl = function( url, options, doc ) {
+ return jQuery.ajax( {
+ url: url,
+
+ // Make this explicit, since user can override this through ajaxSetup (#11264)
+ type: "GET",
+ dataType: "script",
+ cache: true,
+ async: false,
+ global: false,
+
+ // Only evaluate the response if it is successful (gh-4126)
+ // dataFilter is not invoked for failure responses, so using it instead
+ // of the default converter is kludgy but it works.
+ converters: {
+ "text script": function() {}
+ },
+ dataFilter: function( response ) {
+ jQuery.globalEval( response, options, doc );
+ }
+ } );
+};
+
+
+jQuery.fn.extend( {
+ wrapAll: function( html ) {
+ var wrap;
+
+ if ( this[ 0 ] ) {
+ if ( isFunction( html ) ) {
+ html = html.call( this[ 0 ] );
+ }
+
+ // The elements to wrap the target around
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
+ }
+
+ wrap.map( function() {
+ var elem = this;
+
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
+ }
+
+ return elem;
+ } ).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( isFunction( html ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).wrapInner( html.call( this, i ) );
+ } );
+ }
+
+ return this.each( function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ } );
+ },
+
+ wrap: function( html ) {
+ var htmlIsFunction = isFunction( html );
+
+ return this.each( function( i ) {
+ jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
+ } );
+ },
+
+ unwrap: function( selector ) {
+ this.parent( selector ).not( "body" ).each( function() {
+ jQuery( this ).replaceWith( this.childNodes );
+ } );
+ return this;
+ }
+} );
+
+
+jQuery.expr.pseudos.hidden = function( elem ) {
+ return !jQuery.expr.pseudos.visible( elem );
+};
+jQuery.expr.pseudos.visible = function( elem ) {
+ return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
+};
+
+
+
+
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch ( e ) {}
+};
+
+var xhrSuccessStatus = {
+
+ // File protocol always yields status code 0, assume 200
+ 0: 200,
+
+ // Support: IE <=9 only
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport( function( options ) {
+ var callback, errorCallback;
+
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr();
+
+ xhr.open(
+ options.type,
+ options.url,
+ options.async,
+ options.username,
+ options.password
+ );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ callback = errorCallback = xhr.onload =
+ xhr.onerror = xhr.onabort = xhr.ontimeout =
+ xhr.onreadystatechange = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+
+ // Support: IE <=9 only
+ // On a manual native abort, IE9 throws
+ // errors on any property access that is not readyState
+ if ( typeof xhr.status !== "number" ) {
+ complete( 0, "error" );
+ } else {
+ complete(
+
+ // File: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
+ }
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+
+ // Support: IE <=9 only
+ // IE9 has no XHR2 but throws on binary (trac-11426)
+ // For XHR2 non-text, let the caller handle it (gh-2498)
+ ( xhr.responseType || "text" ) !== "text" ||
+ typeof xhr.responseText !== "string" ?
+ { binary: xhr.response } :
+ { text: xhr.responseText },
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
+
+ // Support: IE 9 only
+ // Use onreadystatechange to replace onabort
+ // to handle uncaught aborts
+ if ( xhr.onabort !== undefined ) {
+ xhr.onabort = errorCallback;
+ } else {
+ xhr.onreadystatechange = function() {
+
+ // Check readyState before timeout as it changes
+ if ( xhr.readyState === 4 ) {
+
+ // Allow onerror to be called first,
+ // but that will not handle a native abort
+ // Also, save errorCallback to a variable
+ // as xhr.onerror cannot be accessed
+ window.setTimeout( function() {
+ if ( callback ) {
+ errorCallback();
+ }
+ } );
+ }
+ };
+ }
+
+ // Create the abort callback
+ callback = callback( "abort" );
+
+ try {
+
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+
+ // #14683: Only rethrow if this hasn't been notified as an error yet
+ if ( callback ) {
+ throw e;
+ }
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
+jQuery.ajaxPrefilter( function( s ) {
+ if ( s.crossDomain ) {
+ s.contents.script = false;
+ }
+} );
+
+// Install script dataType
+jQuery.ajaxSetup( {
+ accepts: {
+ script: "text/javascript, application/javascript, " +
+ "application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /\b(?:java|ecma)script\b/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+} );
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ }
+} );
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+
+ // This transport only deals with cross domain or forced-by-attrs requests
+ if ( s.crossDomain || s.scriptAttrs ) {
+ var script, callback;
+ return {
+ send: function( _, complete ) {
+ script = jQuery( "<script>" )
+ .attr( s.scriptAttrs || {} )
+ .prop( { charset: s.scriptCharset, src: s.url } )
+ .on( "load error", callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
+ }
+ } );
+
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ document.head.appendChild( script[ 0 ] );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup( {
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+} );
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" &&
+ ( s.contentType || "" )
+ .indexOf( "application/x-www-form-urlencoded" ) === 0 &&
+ rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters[ "script json" ] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // Force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always( function() {
+
+ // If previous value didn't exist - remove it
+ if ( overwritten === undefined ) {
+ jQuery( window ).removeProp( callbackName );
+
+ // Otherwise restore preexisting value
+ } else {
+ window[ callbackName ] = overwritten;
+ }
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+
+ // Make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // Save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ } );
+
+ // Delegate to script
+ return "script";
+ }
+} );
+
+
+
+
+// Support: Safari 8 only
+// In Safari 8 documents created via document.implementation.createHTMLDocument
+// collapse sibling forms: the second one becomes a child of the first one.
+// Because of that, this security measure has to be disabled in Safari 8.
+// https://bugs.webkit.org/show_bug.cgi?id=137337
+support.createHTMLDocument = ( function() {
+ var body = document.implementation.createHTMLDocument( "" ).body;
+ body.innerHTML = "<form></form><form></form>";
+ return body.childNodes.length === 2;
+} )();
+
+
+// Argument "data" should be string of html
+// context (optional): If specified, the fragment will be created in this context,
+// defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( typeof data !== "string" ) {
+ return [];
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+
+ var base, parsed, scripts;
+
+ if ( !context ) {
+
+ // Stop scripts or inline event handlers from being executed immediately
+ // by using document.implementation
+ if ( support.createHTMLDocument ) {
+ context = document.implementation.createHTMLDocument( "" );
+
+ // Set the base href for the created document
+ // so any parsed elements with URLs
+ // are based on the document's URL (gh-2965)
+ base = context.createElement( "base" );
+ base.href = document.location.href;
+ context.head.appendChild( base );
+ } else {
+ context = document;
+ }
+ }
+
+ parsed = rsingleTag.exec( data );
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[ 1 ] ) ];
+ }
+
+ parsed = buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ var selector, type, response,
+ self = this,
+ off = url.indexOf( " " );
+
+ if ( off > -1 ) {
+ selector = stripAndCollapse( url.slice( off ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax( {
+ url: url,
+
+ // If "type" variable is undefined, then "GET" method will be used.
+ // Make value of this field explicit since
+ // user can override it through ajaxSetup method
+ type: type || "GET",
+ dataType: "html",
+ data: params
+ } ).done( function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ // If the request succeeds, this function gets "data", "status", "jqXHR"
+ // but they are ignored because response was set above.
+ // If it fails, this function gets "jqXHR", "status", "error"
+ } ).always( callback && function( jqXHR, status ) {
+ self.each( function() {
+ callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
+ } );
+ } );
+ }
+
+ return this;
+};
+
+
+
+
+jQuery.expr.pseudos.animated = function( elem ) {
+ return jQuery.grep( jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ } ).length;
+};
+
+
+
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // Set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
+
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( isFunction( options ) ) {
+
+ // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+ options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend( {
+
+ // offset() relates an element's border box to the document origin
+ offset: function( options ) {
+
+ // Preserve chaining for setter
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each( function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ } );
+ }
+
+ var rect, win,
+ elem = this[ 0 ];
+
+ if ( !elem ) {
+ return;
+ }
+
+ // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a
+ // disconnected node in IE throws an error
+ if ( !elem.getClientRects().length ) {
+ return { top: 0, left: 0 };
+ }
+
+ // Get document-relative position by adding viewport scroll to viewport-relative gBCR
+ rect = elem.getBoundingClientRect();
+ win = elem.ownerDocument.defaultView;
+ return {
+ top: rect.top + win.pageYOffset,
+ left: rect.left + win.pageXOffset
+ };
+ },
+
+ // position() relates an element's margin box to its offset parent's padding box
+ // This corresponds to the behavior of CSS absolute positioning
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset, doc,
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
+
+ // position:fixed elements are offset from the viewport, which itself always has zero offset
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+
+ // Assume position:fixed implies availability of getBoundingClientRect
+ offset = elem.getBoundingClientRect();
+
+ } else {
+ offset = this.offset();
+
+ // Account for the *real* offset parent, which can be the document or its root element
+ // when a statically positioned element is identified
+ doc = elem.ownerDocument;
+ offsetParent = elem.offsetParent || doc.documentElement;
+ while ( offsetParent &&
+ ( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
+ jQuery.css( offsetParent, "position" ) === "static" ) {
+
+ offsetParent = offsetParent.parentNode;
+ }
+ if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
+
+ // Incorporate borders into its offset, since they are outside its content origin
+ parentOffset = jQuery( offsetParent ).offset();
+ parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
+ }
+ }
+
+ // Subtract parent offsets and element margins
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+ };
+ },
+
+ // This method will return documentElement in the following cases:
+ // 1) For the element inside the iframe without offsetParent, this method will return
+ // documentElement of the parent window
+ // 2) For the hidden or detached element
+ // 3) For body or html element, i.e. in case of the html node - it will return itself
+ //
+ // but those exceptions were never presented as a real life use-cases
+ // and might be considered as more preferable results.
+ //
+ // This logic, however, is not guaranteed and can change at any point in the future
+ offsetParent: function() {
+ return this.map( function() {
+ var offsetParent = this.offsetParent;
+
+ while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || documentElement;
+ } );
+ }
+} );
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+
+ // Coalesce documents and windows
+ var win;
+ if ( isWindow( elem ) ) {
+ win = elem;
+ } else if ( elem.nodeType === 9 ) {
+ win = elem.defaultView;
+ }
+
+ if ( val === undefined ) {
+ return win ? win[ prop ] : elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : win.pageXOffset,
+ top ? val : win.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length );
+ };
+} );
+
+// Support: Safari <=7 - 9.1, Chrome <=37 - 49
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( _i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+
+ // If curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+} );
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( {
+ padding: "inner" + name,
+ content: type,
+ "": "outer" + name
+ }, function( defaultExtra, funcName ) {
+
+ // Margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( isWindow( elem ) ) {
+
+ // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
+ return funcName.indexOf( "outer" ) === 0 ?
+ elem[ "inner" + name ] :
+ elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable );
+ };
+ } );
+} );
+
+
+jQuery.each( [
+ "ajaxStart",
+ "ajaxStop",
+ "ajaxComplete",
+ "ajaxError",
+ "ajaxSuccess",
+ "ajaxSend"
+], function( _i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+} );
+
+
+
+
+jQuery.fn.extend( {
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ?
+ this.off( selector, "**" ) :
+ this.off( types, selector || "**", fn );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+} );
+
+jQuery.each(
+ ( "blur focus focusin focusout resize scroll click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+ function( _i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+ }
+);
+
+
+
+
+// Support: Android <=4.0 only
+// Make sure we trim BOM and NBSP
+var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+
+// Bind a function to a context, optionally partially applying any
+// arguments.
+// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
+// However, it is not slated for removal any time soon
+jQuery.proxy = function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+};
+
+jQuery.holdReady = function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+};
+jQuery.isArray = Array.isArray;
+jQuery.parseJSON = JSON.parse;
+jQuery.nodeName = nodeName;
+jQuery.isFunction = isFunction;
+jQuery.isWindow = isWindow;
+jQuery.camelCase = camelCase;
+jQuery.type = toType;
+
+jQuery.now = Date.now;
+
+jQuery.isNumeric = function( obj ) {
+
+ // As of jQuery 3.0, isNumeric is limited to
+ // strings and numbers (primitives or objects)
+ // that can be coerced to finite numbers (gh-2662)
+ var type = jQuery.type( obj );
+ return ( type === "number" || type === "string" ) &&
+
+ // parseFloat NaNs numeric-cast false positives ("")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ !isNaN( obj - parseFloat( obj ) );
+};
+
+jQuery.trim = function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+};
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ } );
+}
+
+
+
+
+var
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === "undefined" ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+} );
diff --git a/asset/js/jquery/jquery.min.js b/asset/js/jquery/jquery.min.js
new file mode 100644
index 0000000..c4c6022
--- /dev/null
+++ b/asset/js/jquery/jquery.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
diff --git a/bin/make-release.sh b/bin/make-release.sh
new file mode 100755
index 0000000..4c603e7
--- /dev/null
+++ b/bin/make-release.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+VERSION="$1"
+NO_OPT="$2"
+
+if [[ -z $VERSION ]]; then
+ echo "USAGE: $0 <version> [--no-tag|--no-checkout]"
+ echo " e.g.: $0 0.1.0"
+ exit 1
+fi
+
+function fail {
+ local msg="$1"
+ echo "ERROR: $msg"
+ exit 1
+}
+
+TAG=$(git tag | grep -c "$VERSION")
+
+if [[ "$TAG" -ne "0" ]]; then
+ echo -n "Version $VERSION has already been tagged: "
+ git tag | grep "$VERSION"
+ exit 1
+fi
+
+if [ "$NO_OPT" != "--no-checkout" ]; then
+ BRANCH="stable/$VERSION"
+ git checkout -b "$BRANCH" || fail "Version branch $BRANCH already exists"
+else
+ BRANCH=$(git rev-parse --abbrev-ref HEAD)
+fi
+
+git rm -rf vendor
+rm -rf vendor
+rm -f composer.lock
+composer install || fail "composer install failed"
+find vendor/ -type f -name "*.php" \
+ | grep -v '/examples/' \
+ | grep -v '/example/' \
+ | grep -v '/tests/' \
+ | grep -v '/test/' \
+ | xargs -L1 git add -f
+find vendor/ -type f -name LICENSE | xargs -L1 git add -f
+find vendor/ -type f -name '*.json' | xargs -L1 git add -f
+find asset/ -type f | xargs -L1 git add -f
+echo "v$VERSION" > VERSION
+git add VERSION
+git add composer.lock -f
+git commit -m "Version v$VERSION"
+
+rm -rf vendor
+git checkout vendor
+composer validate --no-check-all --strict || fail "Composer validate failed"
+
+if [ -z "$NO_OPT" ]; then
+ git tag -a v$VERSION -m "Version v$VERSION"
+ echo "Finished, tagged v$VERSION"
+ echo "Now please run:"
+else
+ echo "Finished, but not tagged yet"
+ echo "Now please run:"
+ echo "git tag -s v$VERSION -m \"Version v$VERSION\""
+fi
+
+echo "git push origin "$BRANCH":"$BRANCH" && git push --tags"
diff --git a/bin/make-snapshot.sh b/bin/make-snapshot.sh
new file mode 100755
index 0000000..c2c60a0
--- /dev/null
+++ b/bin/make-snapshot.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -xe
+
+BRANCH="$1"
+
+if [ -z $BRANCH ]; then
+ echo "USAGE: $0 <branch>"
+ echo " e.g.: $0 snapshot/nightly"
+ exit 1
+fi
+
+LATEST_TAG=$(git for-each-ref refs/tags --sort=-taggerdate --format='%(refname)' --count=1 | awk -F/ '{print $3}')
+NEXT_VERSION=$(echo "${LATEST_TAG:1}" | awk -F. -v OFS=. '{$3=0}; {++$2}; {print}')
+
+if [[ -n $(git branch | grep $BRANCH) ]]; then
+ git branch -D $BRANCH
+fi
+
+git checkout -b $BRANCH
+git merge --no-ff -m "Merge latest tag, to make it reachable for git-describe" $LATEST_TAG
+
+git commit -a -m "Require dev-master everywhere"
+bin/make-release.sh "$NEXT_VERSION-dev" --no-checkout
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..a0ec7a0
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,69 @@
+{
+ "name": "icinga/icinga-php-thirdparty",
+ "type": "project",
+ "description": "Icinga Web 2 - Bundle for all 3rd party PHP libraries",
+ "homepage": "https://github.com/Icinga/icinga-php-thirdparty",
+ "license": "MIT",
+ "config": {
+ "sort-packages": true,
+ "platform": {
+ "php": "7.2"
+ },
+ "allow-plugins": {
+ "cweagans/composer-patches": true
+ }
+ },
+ "support": {
+ "issues": "https://github.com/Icinga/icinga-php-thirdparty/issues"
+ },
+ "require": {
+ "php": ">=7.2 <=8.1",
+ "ext-curl": "*",
+ "clue/block-react": "^1",
+ "clue/connection-manager-extra": "^1",
+ "clue/http-proxy-react": "^1",
+ "clue/mq-react": "^1",
+ "clue/redis-react": "^2",
+ "clue/soap-react": "^1",
+ "clue/socket-raw": "^1",
+ "clue/socks-react": "^1",
+ "clue/stdio-react": "^2",
+ "cweagans/composer-patches": "~1.0",
+ "evenement/evenement": "^3",
+ "predis/predis": "^1",
+ "psr/http-message": "^1",
+ "ramsey/uuid": "^3",
+ "react/child-process": "^0.6",
+ "react/datagram": "^1",
+ "react/dns": "^1",
+ "react/event-loop": "^1",
+ "react/http": "^1",
+ "react/promise": "^2",
+ "react/promise-stream": "^1",
+ "react/promise-timer": "^1",
+ "react/socket": "^1",
+ "react/stream": "^1",
+ "guzzlehttp/psr7": "^1",
+ "guzzlehttp/guzzle": "^6.5",
+ "jfcherng/php-diff": "^6.10",
+ "components/jquery": "3.6.*"
+ },
+ "require-dev": {
+ },
+ "autoload": {
+ "psr-0": { "AssetLoader": "" }
+ },
+ "scripts": {
+ "post-update-cmd": [
+ "AssetLoader::update"
+ ]
+ },
+ "extra": {
+ "composer-exit-on-patch-failure": true,
+ "patches": {
+ "ramsey/uuid": {
+ "Uuid: Add PHP 8.1 support": "patches/ramsey-uuid.patch"
+ }
+ }
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..bc40e23
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,3311 @@
+{
+ "_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#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "5e4037f794a815c31caaa20dd7430923",
+ "packages": [
+ {
+ "name": "clue/block-react",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-block.git",
+ "reference": "718b0571a94aa693c6fffc72182e87257ac900f3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-block/zipball/718b0571a94aa693c6fffc72182e87257ac900f3",
+ "reference": "718b0571a94aa693c6fffc72182e87257ac900f3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/http": "^1.4"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Lightweight library that eases integrating async components built for ReactPHP in a traditional, blocking environment.",
+ "homepage": "https://github.com/clue/reactphp-block",
+ "keywords": [
+ "async",
+ "await",
+ "blocking",
+ "event loop",
+ "promise",
+ "reactphp",
+ "sleep",
+ "synchronous"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-block/issues",
+ "source": "https://github.com/clue/reactphp-block/tree/v1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-10-20T14:07:33+00:00"
+ },
+ {
+ "name": "clue/buzz-react",
+ "version": "v2.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-buzz.git",
+ "reference": "eb180b5e0db00a3febaa458289706b8ca80ffe2a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-buzz/zipball/eb180b5e0db00a3febaa458289706b8ca80ffe2a",
+ "reference": "eb180b5e0db00a3febaa458289706b8ca80ffe2a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/http-client": "^0.5.10",
+ "react/promise": "^2.2.1 || ^1.2.1",
+ "react/promise-stream": "^1.0 || ^0.1.2",
+ "react/socket": "^1.1",
+ "react/stream": "^1.0 || ^0.7",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "clue/http-proxy-react": "^1.3",
+ "clue/reactphp-ssh-proxy": "^1.0",
+ "clue/socks-react": "^1.0",
+ "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35",
+ "react/http": "^0.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Buzz\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Simple, async PSR-7 HTTP client for concurrently processing any number of HTTP requests, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-buzz",
+ "keywords": [
+ "async",
+ "http",
+ "http client",
+ "psr-7",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-buzz/issues",
+ "source": "https://github.com/clue/reactphp-buzz/tree/v2.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "abandoned": "react/http",
+ "time": "2020-07-03T10:43:43+00:00"
+ },
+ {
+ "name": "clue/connection-manager-extra",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-connection-manager-extra.git",
+ "reference": "95e7033af27a74a793b30dc9f049fbaf93de2c2c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-connection-manager-extra/zipball/95e7033af27a74a793b30dc9f049fbaf93de2c2c",
+ "reference": "95e7033af27a74a793b30dc9f049fbaf93de2c2c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/promise-timer": "^1.1",
+ "react/socket": "^1.0 || ^0.8 || ^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "ConnectionManager\\Extra\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Extra decorators for creating async TCP/IP connections, built on top of ReactPHP's Socket component",
+ "homepage": "https://github.com/clue/reactphp-connection-manager-extra",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "acl",
+ "delay",
+ "firewall",
+ "network",
+ "random",
+ "reactphp",
+ "reject",
+ "repeat",
+ "retry",
+ "timeout"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-connection-manager-extra/issues",
+ "source": "https://github.com/clue/reactphp-connection-manager-extra/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-12-12T15:42:48+00:00"
+ },
+ {
+ "name": "clue/http-proxy-react",
+ "version": "v1.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-http-proxy.git",
+ "reference": "8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8",
+ "reference": "8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": " ^2.1 || ^1.2.1",
+ "react/socket": "^1.9",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\HttpProxy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-http-proxy",
+ "keywords": [
+ "async",
+ "connect",
+ "http",
+ "proxy",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-http-proxy/issues",
+ "source": "https://github.com/clue/reactphp-http-proxy/tree/v1.7.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-08-06T13:05:41+00:00"
+ },
+ {
+ "name": "clue/mq-react",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-mq.git",
+ "reference": "3f2ea2c2947522022ba5ff6c52267fa3f2c0f193"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-mq/zipball/3f2ea2c2947522022ba5ff6c52267fa3f2c0f193",
+ "reference": "3f2ea2c2947522022ba5ff6c52267fa3f2c0f193",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.2.1 || ^1.2.1"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Mq\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-mq",
+ "keywords": [
+ "Mini Queue",
+ "async",
+ "concurrency",
+ "job",
+ "message",
+ "message queue",
+ "queue",
+ "rate limit",
+ "reactphp",
+ "throttle",
+ "worker"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-mq/issues",
+ "source": "https://github.com/clue/reactphp-mq/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-11-15T10:50:53+00:00"
+ },
+ {
+ "name": "clue/redis-protocol",
+ "version": "v0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/php-redis-protocol.git",
+ "reference": "271b8009887209d930f613ad3b9518f94bd6b51c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/php-redis-protocol/zipball/271b8009887209d930f613ad3b9518f94bd6b51c",
+ "reference": "271b8009887209d930f613ad3b9518f94bd6b51c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Clue\\Redis\\Protocol": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "keywords": [
+ "parser",
+ "protocol",
+ "redis",
+ "serializer",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/php-redis-protocol/issues",
+ "source": "https://github.com/clue/php-redis-protocol/tree/v0.3.1"
+ },
+ "time": "2017-06-06T16:07:10+00:00"
+ },
+ {
+ "name": "clue/redis-react",
+ "version": "v2.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-redis.git",
+ "reference": "f911455f9d7a77dd6f39c22548ddff521544b291"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/f911455f9d7a77dd6f39c22548ddff521544b291",
+ "reference": "f911455f9d7a77dd6f39c22548ddff521544b291",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-protocol": "0.3.*",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.0 || ^1.1",
+ "react/promise-timer": "^1.8",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Redis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async Redis client implementation, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-redis",
+ "keywords": [
+ "async",
+ "client",
+ "database",
+ "reactphp",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-redis/issues",
+ "source": "https://github.com/clue/reactphp-redis/tree/v2.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-05-09T09:50:02+00:00"
+ },
+ {
+ "name": "clue/soap-react",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-soap.git",
+ "reference": "72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-soap/zipball/72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393",
+ "reference": "72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393",
+ "shasum": ""
+ },
+ "require": {
+ "clue/buzz-react": "^2.5",
+ "ext-soap": "*",
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Soap\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "Simple, async SOAP webservice client library, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-soap",
+ "keywords": [
+ "reactphp",
+ "soap",
+ "soapclient",
+ "webservice",
+ "wsdl"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-soap/issues",
+ "source": "https://github.com/clue/reactphp-soap/tree/v1.0.0"
+ },
+ "time": "2018-11-07T17:19:24+00:00"
+ },
+ {
+ "name": "clue/socket-raw",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/socket-raw.git",
+ "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/socket-raw/zipball/91e9f619f6769f931454a9882c21ffd7623d06cb",
+ "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-sockets": "*",
+ "php": ">=5.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Socket\\Raw\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets).",
+ "homepage": "https://github.com/clue/socket-raw",
+ "keywords": [
+ "Socket",
+ "client",
+ "datagram",
+ "dgram",
+ "icmp",
+ "ipv6",
+ "server",
+ "stream",
+ "tcp",
+ "udg",
+ "udp",
+ "unix"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/socket-raw/issues",
+ "source": "https://github.com/clue/socket-raw/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-04-14T14:58:06+00:00"
+ },
+ {
+ "name": "clue/socks-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-socks.git",
+ "reference": "f90edf489313301e87292c51d41faf8c21138513"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-socks/zipball/f90edf489313301e87292c51d41faf8c21138513",
+ "reference": "f90edf489313301e87292c51d41faf8c21138513",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "clue/connection-manager-extra": "^1.0 || ^0.7",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Socks\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-socks",
+ "keywords": [
+ "async",
+ "proxy server",
+ "reactphp",
+ "socks client",
+ "socks server",
+ "socks4a",
+ "socks5",
+ "tcp tunnel"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-socks/issues",
+ "source": "https://github.com/clue/reactphp-socks/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-08-06T13:06:59+00:00"
+ },
+ {
+ "name": "clue/stdio-react",
+ "version": "v2.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-stdio.git",
+ "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-stdio/zipball/dfa6c378aabdff718202d4e2453f752c38ea3399",
+ "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399",
+ "shasum": ""
+ },
+ "require": {
+ "clue/term-react": "^1.0 || ^0.1.1",
+ "clue/utf8-react": "^1.0 || ^0.1",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/arguments": "^2.0",
+ "clue/commander": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Stdio\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async, event-driven console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-stdio",
+ "keywords": [
+ "async",
+ "autocomplete",
+ "autocompletion",
+ "cli",
+ "history",
+ "interactive",
+ "reactphp",
+ "readline",
+ "stdin",
+ "stdio",
+ "stdout"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-stdio/issues",
+ "source": "https://github.com/clue/reactphp-stdio/tree/v2.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-03-18T15:09:30+00:00"
+ },
+ {
+ "name": "clue/term-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-term.git",
+ "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-term/zipball/eb6eb063eda04a714ef89f066586a2c49588f7ca",
+ "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Term\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming terminal emulator, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-term",
+ "keywords": [
+ "C0",
+ "CSI",
+ "ansi",
+ "apc",
+ "ascii",
+ "c1",
+ "control codes",
+ "dps",
+ "osc",
+ "pm",
+ "reactphp",
+ "streaming",
+ "terminal",
+ "vt100",
+ "xterm"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-term/issues",
+ "source": "https://github.com/clue/reactphp-term/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-06T11:50:12+00:00"
+ },
+ {
+ "name": "clue/utf8-react",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-utf8.git",
+ "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-utf8/zipball/8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
+ "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4 || ^0.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 ||^5.7 || ^4.8",
+ "react/stream": "^1.0 || ^0.7"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Utf8\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming UTF-8 parser, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-utf8",
+ "keywords": [
+ "reactphp",
+ "streaming",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-utf8/issues",
+ "source": "https://github.com/clue/reactphp-utf8/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-06T11:48:09+00:00"
+ },
+ {
+ "name": "components/jquery",
+ "version": "3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/components/jquery.git",
+ "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/components/jquery/zipball/6cf38ee1fd04b6adf8e7dda161283aa35be818c3",
+ "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3",
+ "shasum": ""
+ },
+ "type": "component",
+ "extra": {
+ "component": {
+ "scripts": [
+ "jquery.js"
+ ],
+ "files": [
+ "jquery.min.js",
+ "jquery.min.map",
+ "jquery.slim.js",
+ "jquery.slim.min.js",
+ "jquery.slim.min.map"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "JS Foundation and other contributors"
+ }
+ ],
+ "description": "jQuery JavaScript Library",
+ "homepage": "http://jquery.com",
+ "support": {
+ "forum": "http://forum.jquery.com",
+ "irc": "irc://irc.freenode.org/jquery",
+ "issues": "https://github.com/jquery/jquery/issues",
+ "source": "https://github.com/jquery/jquery",
+ "wiki": "http://docs.jquery.com/"
+ },
+ "time": "2021-03-20T19:13:42+00:00"
+ },
+ {
+ "name": "cweagans/composer-patches",
+ "version": "1.7.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cweagans/composer-patches.git",
+ "reference": "e9969cfc0796e6dea9b4e52f77f18e1065212871"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e9969cfc0796e6dea9b4e52f77f18e1065212871",
+ "reference": "e9969cfc0796e6dea9b4e52f77f18e1065212871",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0 || ^2.0",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "composer/composer": "~1.0 || ~2.0",
+ "phpunit/phpunit": "~4.6"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "cweagans\\Composer\\Patches"
+ },
+ "autoload": {
+ "psr-4": {
+ "cweagans\\Composer\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Cameron Eagans",
+ "email": "me@cweagans.net"
+ }
+ ],
+ "description": "Provides a way to patch Composer packages.",
+ "support": {
+ "issues": "https://github.com/cweagans/composer-patches/issues",
+ "source": "https://github.com/cweagans/composer-patches/tree/1.7.2"
+ },
+ "time": "2022-01-25T19:21:20+00:00"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
+ "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Evenement": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/master"
+ },
+ "time": "2017-07-23T21:35:13+00:00"
+ },
+ {
+ "name": "fig/http-message-util",
+ "version": "1.1.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message-util.git",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 || ^7.0 || ^8.0"
+ },
+ "suggest": {
+ "psr/http-message": "The package containing the PSR-7 interfaces"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Fig\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/http-message-util/issues",
+ "source": "https://github.com/php-fig/http-message-util/tree/1.1.5"
+ },
+ "time": "2020-11-24T22:02:12+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.5.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "724562fa861e21a4071c652c8a159934e4f05592"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/724562fa861e21a4071c652c8a159934e4f05592",
+ "reference": "724562fa861e21a4071c652c8a159934e4f05592",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1",
+ "php": ">=5.5",
+ "symfony/polyfill-intl-idn": "^1.17.0"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.5-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/6.5.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-06-09T21:36:50+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "1.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
+ "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.5-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/1.5.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-10-22T20:56:57+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.8.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/337e3ad8e5716c15f9657bd214d16cc5e69df268",
+ "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "ext-zlib": "*",
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
+ },
+ "suggest": {
+ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.7-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/psr7/issues",
+ "source": "https://github.com/guzzle/psr7/tree/1.8.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-03-20T21:51:18+00:00"
+ },
+ {
+ "name": "jfcherng/php-color-output",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-color-output.git",
+ "reference": "2673074597eca9682d2fdfaee39a22418d4cc2f6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-color-output/zipball/2673074597eca9682d2fdfaee39a22418d4cc2f6",
+ "reference": "2673074597eca9682d2fdfaee39a22418d4cc2f6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.15",
+ "phan/phan": "^2.2",
+ "phpunit/phpunit": "^7.2 || ^8.2 || ^9",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/helpers.php"
+ ],
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "Make your PHP command-line application colorful.",
+ "keywords": [
+ "ansi-colors",
+ "color",
+ "command-line",
+ "str-color"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-color-output/issues",
+ "source": "https://github.com/jfcherng/php-color-output/tree/2.0.2"
+ },
+ "time": "2020-05-27T19:24:44+00:00"
+ },
+ {
+ "name": "jfcherng/php-diff",
+ "version": "6.10.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-diff.git",
+ "reference": "ccc178b81ac737b0f9a60e7210d26d5ed797e786"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-diff/zipball/ccc178b81ac737b0f9a60e7210d26d5ed797e786",
+ "reference": "ccc178b81ac737b0f9a60e7210d26d5ed797e786",
+ "shasum": ""
+ },
+ "require": {
+ "jfcherng/php-color-output": "^2.0",
+ "jfcherng/php-mb-string": "^1.4.6",
+ "jfcherng/php-sequence-matcher": "^3.2.8",
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A comprehensive library for generating differences between two strings in multiple formats (unified, side by side HTML etc).",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-diff/issues",
+ "source": "https://github.com/jfcherng/php-diff/tree/6.10.4"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2022-04-02T16:36:51+00:00"
+ },
+ {
+ "name": "jfcherng/php-mb-string",
+ "version": "1.4.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-mb-string.git",
+ "reference": "f5b438d348e030961e0b86a04ef2319c31ae8146"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-mb-string/zipball/f5b438d348e030961e0b86a04ef2319c31ae8146",
+ "reference": "f5b438d348e030961e0b86a04ef2319c31ae8146",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.18",
+ "phan/phan": "^2 || ^3 || ^4",
+ "phpunit/phpunit": "^7.2 || ^8 || ^9"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "A high performance multibytes sting implementation for frequently reading/writing operations.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-mb-string/issues",
+ "source": "https://github.com/jfcherng/php-mb-string/tree/1.4.6"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2022-04-02T16:32:41+00:00"
+ },
+ {
+ "name": "jfcherng/php-sequence-matcher",
+ "version": "3.2.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-sequence-matcher.git",
+ "reference": "410519ca07cd7989f450d6e2aa40975dbd1be048"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-sequence-matcher/zipball/410519ca07cd7989f450d6e2aa40975dbd1be048",
+ "reference": "410519ca07cd7989f450d6e2aa40975dbd1be048",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4 || ^5",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A longest sequence matcher. The logic is primarily based on the Python difflib package.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-sequence-matcher/issues",
+ "source": "https://github.com/jfcherng/php-sequence-matcher/tree/3.2.8"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "time": "2021-09-02T04:02:02+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "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",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "time": "2020-10-15T08:29:30+00:00"
+ },
+ {
+ "name": "predis/predis",
+ "version": "v1.1.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/predis/predis.git",
+ "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/predis/predis/zipball/a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e",
+ "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "suggest": {
+ "ext-curl": "Allows access to Webdis when paired with phpiredis",
+ "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Predis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniele Alessandri",
+ "email": "suppakilla@gmail.com",
+ "homepage": "http://clorophilla.net",
+ "role": "Creator & Maintainer"
+ },
+ {
+ "name": "Till Krüss",
+ "homepage": "https://till.im",
+ "role": "Maintainer"
+ }
+ ],
+ "description": "Flexible and feature-complete Redis client for PHP and HHVM",
+ "homepage": "http://github.com/predis/predis",
+ "keywords": [
+ "nosql",
+ "predis",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/predis/predis/issues",
+ "source": "https://github.com/predis/predis/tree/v1.1.10"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/tillkruss",
+ "type": "github"
+ }
+ ],
+ "time": "2022-01-05T17:46:08+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/master"
+ },
+ "time": "2016-08-06T14:39:51+00:00"
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "support": {
+ "issues": "https://github.com/ralouphie/getallheaders/issues",
+ "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+ },
+ "time": "2019-03-08T08:55:37+00:00"
+ },
+ {
+ "name": "ramsey/uuid",
+ "version": "3.9.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/uuid.git",
+ "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
+ "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
+ "php": "^5.4 | ^7.0 | ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "replace": {
+ "rhumsaa/uuid": "self.version"
+ },
+ "require-dev": {
+ "codeception/aspect-mock": "^1 | ^2",
+ "doctrine/annotations": "^1.2",
+ "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
+ "mockery/mockery": "^0.9.11 | ^1",
+ "moontoast/math": "^1.1",
+ "nikic/php-parser": "<=4.5.0",
+ "paragonie/random-lib": "^2",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+ "squizlabs/php_codesniffer": "^3.5",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "suggest": {
+ "ext-ctype": "Provides support for PHP Ctype functions",
+ "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+ "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+ "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+ "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+ "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+ "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+ "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ },
+ {
+ "name": "Marijn Huizendveld",
+ "email": "marijn.huizendveld@gmail.com"
+ },
+ {
+ "name": "Thibaud Fabre",
+ "email": "thibaud@aztech.io"
+ }
+ ],
+ "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+ "homepage": "https://github.com/ramsey/uuid",
+ "keywords": [
+ "guid",
+ "identifier",
+ "uuid"
+ ],
+ "support": {
+ "issues": "https://github.com/ramsey/uuid/issues",
+ "rss": "https://github.com/ramsey/uuid/releases.atom",
+ "source": "https://github.com/ramsey/uuid",
+ "wiki": "https://github.com/ramsey/uuid/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ramsey",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-09-25T23:07:42+00:00"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/4bf736a2cccec7298bdf745db77585966fc2ca7e",
+ "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-02-02T06:47:52+00:00"
+ },
+ {
+ "name": "react/child-process",
+ "version": "v0.6.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/a778f3fb828d68caf8a9ab6567fd8342a86f12fe",
+ "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/socket": "^1.8",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\ChildProcess\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven library for executing child processes with ReactPHP.",
+ "keywords": [
+ "event-driven",
+ "process",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/child-process/issues",
+ "source": "https://github.com/reactphp/child-process/tree/v0.6.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-10-12T10:37:07+00:00"
+ },
+ {
+ "name": "react/datagram",
+ "version": "v1.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/datagram.git",
+ "reference": "40f2c39f83541367018605a73b57c99186f7145c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/datagram/zipball/40f2c39f83541367018605a73b57c99186f7145c",
+ "reference": "40f2c39f83541367018605a73b57c99186f7145c",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/dns": "^1.7",
+ "react/event-loop": "^1.2",
+ "react/promise": "~2.1|~1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "~1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Datagram\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven UDP datagram socket client and server for ReactPHP",
+ "homepage": "https://github.com/reactphp/datagram",
+ "keywords": [
+ "Socket",
+ "async",
+ "client",
+ "datagram",
+ "dgram",
+ "reactphp",
+ "server",
+ "udp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/datagram/issues",
+ "source": "https://github.com/reactphp/datagram/tree/v1.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-07-11T13:06:40+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb",
+ "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.8"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-12-20T08:46:54+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/187fb56f46d424afb6ec4ad089269c72eec2e137",
+ "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-event": "~1.0 for ExtEventLoop",
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop",
+ "ext-uv": "* for ExtUvLoop"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-03-17T11:10:22+00:00"
+ },
+ {
+ "name": "react/http",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/http.git",
+ "reference": "59961cc4a5b14481728f07c591546be18fa3a5c7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/http/zipball/59961cc4a5b14481728f07c591546be18fa3a5c7",
+ "reference": "59961cc4a5b14481728f07c591546be18fa3a5c7",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "fig/http-message-util": "^1.1",
+ "php": ">=5.3.0",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.3 || ^1.2.1",
+ "react/promise-stream": "^1.1",
+ "react/socket": "^1.9",
+ "react/stream": "^1.2",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "clue/http-proxy-react": "^1.7",
+ "clue/reactphp-ssh-proxy": "^1.3",
+ "clue/socks-react": "^1.3",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Http\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven, streaming HTTP client and server implementation for ReactPHP",
+ "keywords": [
+ "async",
+ "client",
+ "event-driven",
+ "http",
+ "http client",
+ "http server",
+ "https",
+ "psr-7",
+ "reactphp",
+ "server",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/http/issues",
+ "source": "https://github.com/reactphp/http/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-02-03T13:17:37+00:00"
+ },
+ {
+ "name": "react/http-client",
+ "version": "v0.5.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/http-client.git",
+ "reference": "23dddb415b9bd36c81d1c78df63143e65702aa4b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/http-client/zipball/23dddb415b9bd36c81d1c78df63143e65702aa4b",
+ "reference": "23dddb415b9bd36c81d1c78df63143e65702aa4b",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/socket": "^1.0 || ^0.8.4",
+ "react/stream": "^1.0 || ^0.7.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\HttpClient\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Event-driven, streaming HTTP client for ReactPHP",
+ "keywords": [
+ "http"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/http-client/issues",
+ "source": "https://github.com/reactphp/http-client/tree/v0.5.11"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "abandoned": "react/http",
+ "time": "2021-04-07T16:49:17+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v2.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v2.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-02-11T10:27:51+00:00"
+ },
+ {
+ "name": "react/promise-stream",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-stream.git",
+ "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/3ebd94fe0d8edbf44937948af28d02d5437e9949",
+ "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise-timer": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "The missing link between Promise-land and Stream-land for ReactPHP",
+ "homepage": "https://github.com/reactphp/promise-stream",
+ "keywords": [
+ "Buffer",
+ "async",
+ "promise",
+ "reactphp",
+ "stream",
+ "unwrap"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-stream/issues",
+ "source": "https://github.com/reactphp/promise-stream/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-10-18T10:47:09+00:00"
+ },
+ {
+ "name": "react/promise-timer",
+ "version": "v1.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-timer.git",
+ "reference": "aa7a73c74b8d8c0f622f5982ff7b0351bc29e495"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/aa7a73c74b8d8c0f622f5982ff7b0351bc29e495",
+ "reference": "aa7a73c74b8d8c0f622f5982ff7b0351bc29e495",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Timer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+ "homepage": "https://github.com/reactphp/promise-timer",
+ "keywords": [
+ "async",
+ "event-loop",
+ "promise",
+ "reactphp",
+ "timeout",
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-timer/issues",
+ "source": "https://github.com/reactphp/promise-timer/tree/v1.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-06-13T13:41:03+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/f474156aaab4f09041144fa8b57c7d70aed32a1c",
+ "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.8",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.6.0 || ^1.2.1",
+ "react/promise-timer": "^1.8",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.11.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-01-14T10:14:32+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
+ "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-07-11T12:37:55+00:00"
+ },
+ {
+ "name": "ringcentral/psr7",
+ "version": "1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ringcentral/psr7.git",
+ "reference": "360faaec4b563958b673fb52bbe94e37f14bc686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ringcentral/psr7/zipball/360faaec4b563958b673fb52bbe94e37f14bc686",
+ "reference": "360faaec4b563958b673fb52bbe94e37f14bc686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "~1.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "RingCentral\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "PSR-7 message implementation",
+ "keywords": [
+ "http",
+ "message",
+ "stream",
+ "uri"
+ ],
+ "support": {
+ "source": "https://github.com/ringcentral/psr7/tree/master"
+ },
+ "time": "2018-05-29T20:21:04+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.26.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-24T11:49:31+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-idn",
+ "version": "v1.26.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-idn.git",
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "symfony/polyfill-intl-normalizer": "^1.10",
+ "symfony/polyfill-php72": "^1.10"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Idn\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Laurent Bassin",
+ "email": "laurent@bassin.info"
+ },
+ {
+ "name": "Trevor Rowbotham",
+ "email": "trevor.rowbotham@pm.me"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "idn",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-24T11:49:31+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.26.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "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 intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-24T11:49:31+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php72",
+ "version": "v1.26.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php72.git",
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2",
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php72\\": ""
+ }
+ },
+ "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 backporting some PHP 7.2+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-24T11:49:31+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=7.2 <=8.1",
+ "ext-curl": "*"
+ },
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "7.2"
+ },
+ "plugin-api-version": "2.3.0"
+}
diff --git a/patches/ramsey-uuid.patch b/patches/ramsey-uuid.patch
new file mode 100644
index 0000000..2715351
--- /dev/null
+++ b/patches/ramsey-uuid.patch
@@ -0,0 +1,10 @@
+--- a/vendor/ramsey/uuid/src/Uuid.php
++++ b/vendor/ramsey/uuid/src/Uuid.php
+@@ -212,6 +212,7 @@ class Uuid implements UuidInterface
+ * @return string
+ * @link http://php.net/manual/en/class.jsonserializable.php
+ */
++ #[\ReturnTypeWillChange]
+ public function jsonSerialize()
+ {
+ return $this->toString();
diff --git a/vendor/autoload.php b/vendor/autoload.php
new file mode 100644
index 0000000..e8a1359
--- /dev/null
+++ b/vendor/autoload.php
@@ -0,0 +1,12 @@
+<?php
+
+// autoload.php @generated by Composer
+
+if (PHP_VERSION_ID < 50600) {
+ echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+ exit(1);
+}
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInitd325ec05aa7f058e77e450fa9a6801af::getLoader();
diff --git a/vendor/clue/block-react/LICENSE b/vendor/clue/block-react/LICENSE
new file mode 100644
index 0000000..dc09d1e
--- /dev/null
+++ b/vendor/clue/block-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Christian Lück
+
+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/clue/block-react/composer.json b/vendor/clue/block-react/composer.json
new file mode 100644
index 0000000..ddfc6c8
--- /dev/null
+++ b/vendor/clue/block-react/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "clue/block-react",
+ "description": "Lightweight library that eases integrating async components built for ReactPHP in a traditional, blocking environment.",
+ "keywords": ["blocking", "await", "sleep", "Event Loop", "synchronous", "Promise", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-block",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "files": [ "src/functions_include.php" ]
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Block\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/http": "^1.4"
+ }
+}
diff --git a/vendor/clue/block-react/src/functions.php b/vendor/clue/block-react/src/functions.php
new file mode 100644
index 0000000..6afe2e0
--- /dev/null
+++ b/vendor/clue/block-react/src/functions.php
@@ -0,0 +1,357 @@
+<?php
+
+namespace Clue\React\Block;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\PromiseInterface;
+use React\Promise\Timer;
+use React\Promise\Timer\TimeoutException;
+use Exception;
+use UnderflowException;
+
+/**
+ * Wait/sleep for `$time` seconds.
+ *
+ * ```php
+ * Clue\React\Block\sleep(1.5, $loop);
+ * ```
+ *
+ * This function will only return after the given `$time` has elapsed. In the
+ * meantime, the event loop will run any other events attached to the same loop
+ * until the timer fires. If there are no other events attached to this loop,
+ * it will behave similar to the built-in [`sleep()`](https://www.php.net/manual/en/function.sleep.php).
+ *
+ * Internally, the `$time` argument will be used as a timer for the loop so that
+ * it keeps running until this timer triggers. This implies that if you pass a
+ * really small (or negative) value, it will still start a timer and will thus
+ * trigger at the earliest possible time in the future.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * Note that this function will assume control over the event loop. Internally, it
+ * will actually `run()` the loop until the timer fires and then calls `stop()` to
+ * terminate execution of the loop. This means this function is more suited for
+ * short-lived program executions when using async APIs is not feasible. For
+ * long-running applications, using event-driven APIs by leveraging timers
+ * is usually preferable.
+ *
+ * @param float $time
+ * @param ?LoopInterface $loop
+ * @return void
+ */
+function sleep($time, LoopInterface $loop = null)
+{
+ await(Timer\resolve($time, $loop), $loop);
+}
+
+/**
+ * Block waiting for the given `$promise` to be fulfilled.
+ *
+ * ```php
+ * $result = Clue\React\Block\await($promise, $loop);
+ * ```
+ *
+ * This function will only return after the given `$promise` has settled, i.e.
+ * either fulfilled or rejected. In the meantime, the event loop will run any
+ * events attached to the same loop until the promise settles.
+ *
+ * Once the promise is fulfilled, this function will return whatever the promise
+ * resolved to.
+ *
+ * Once the promise is rejected, this will throw whatever the promise rejected
+ * with. If the promise did not reject with an `Exception`, then this function
+ * will throw an `UnexpectedValueException` instead.
+ *
+ * ```php
+ * try {
+ * $result = Clue\React\Block\await($promise, $loop);
+ * // promise successfully fulfilled with $result
+ * echo 'Result: ' . $result;
+ * } catch (Exception $exception) {
+ * // promise rejected with $exception
+ * echo 'ERROR: ' . $exception->getMessage();
+ * }
+ * ```
+ *
+ * See also the [examples](../examples/).
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * If no `$timeout` argument is given and the promise stays pending, then this
+ * will potentially wait/block forever until the promise is settled. To avoid
+ * this, API authors creating promises are expected to provide means to
+ * configure a timeout for the promise instead. For more details, see also the
+ * [`timeout()` function](https://github.com/reactphp/promise-timer#timeout).
+ *
+ * If the deprecated `$timeout` argument is given and the promise is still pending once the
+ * timeout triggers, this will `cancel()` the promise and throw a `TimeoutException`.
+ * This implies that if you pass a really small (or negative) value, it will still
+ * start a timer and will thus trigger at the earliest possible time in the future.
+ *
+ * Note that this function will assume control over the event loop. Internally, it
+ * will actually `run()` the loop until the promise settles and then calls `stop()` to
+ * terminate execution of the loop. This means this function is more suited for
+ * short-lived promise executions when using promise-based APIs is not feasible.
+ * For long-running applications, using promise-based APIs by leveraging chained
+ * `then()` calls is usually preferable.
+ *
+ * @param PromiseInterface $promise
+ * @param ?LoopInterface $loop
+ * @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
+ * @return mixed returns whatever the promise resolves to
+ * @throws Exception when the promise is rejected
+ * @throws TimeoutException if the $timeout is given and triggers
+ */
+function await(PromiseInterface $promise, LoopInterface $loop = null, $timeout = null)
+{
+ $wait = true;
+ $resolved = null;
+ $exception = null;
+ $rejected = false;
+ $loop = $loop ?: Loop::get();
+
+ if ($timeout !== null) {
+ $promise = Timer\timeout($promise, $timeout, $loop);
+ }
+
+ $promise->then(
+ function ($c) use (&$resolved, &$wait, $loop) {
+ $resolved = $c;
+ $wait = false;
+ $loop->stop();
+ },
+ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
+ $exception = $error;
+ $rejected = true;
+ $wait = false;
+ $loop->stop();
+ }
+ );
+
+ // Explicitly overwrite argument with null value. This ensure that this
+ // argument does not show up in the stack trace in PHP 7+ only.
+ $promise = null;
+
+ while ($wait) {
+ $loop->run();
+ }
+
+ if ($rejected) {
+ if (!$exception instanceof \Exception && !$exception instanceof \Throwable) {
+ $exception = new \UnexpectedValueException(
+ 'Promise rejected with unexpected value of type ' . (is_object($exception) ? get_class($exception) : gettype($exception))
+ );
+ } elseif (!$exception instanceof \Exception) {
+ $exception = new \UnexpectedValueException(
+ 'Promise rejected with unexpected ' . get_class($exception) . ': ' . $exception->getMessage(),
+ $exception->getCode(),
+ $exception
+ );
+ }
+
+ throw $exception;
+ }
+
+ return $resolved;
+}
+
+/**
+ * Wait for ANY of the given promises to be fulfilled.
+ *
+ * ```php
+ * $promises = array(
+ * $promise1,
+ * $promise2
+ * );
+ *
+ * $firstResult = Clue\React\Block\awaitAny($promises, $loop);
+ *
+ * echo 'First result: ' . $firstResult;
+ * ```
+ *
+ * See also the [examples](../examples/).
+ *
+ * This function will only return after ANY of the given `$promises` has been
+ * fulfilled or will throw when ALL of them have been rejected. In the meantime,
+ * the event loop will run any events attached to the same loop.
+ *
+ * Once ANY promise is fulfilled, this function will return whatever this
+ * promise resolved to and will try to `cancel()` all remaining promises.
+ *
+ * Once ALL promises reject, this function will fail and throw an `UnderflowException`.
+ * Likewise, this will throw if an empty array of `$promises` is passed.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * If no `$timeout` argument is given and ALL promises stay pending, then this
+ * will potentially wait/block forever until the promise is fulfilled. To avoid
+ * this, API authors creating promises are expected to provide means to
+ * configure a timeout for the promise instead. For more details, see also the
+ * [`timeout()` function](https://github.com/reactphp/promise-timer#timeout).
+ *
+ * If the deprecated `$timeout` argument is given and ANY promises are still pending once
+ * the timeout triggers, this will `cancel()` all pending promises and throw a
+ * `TimeoutException`. This implies that if you pass a really small (or negative)
+ * value, it will still start a timer and will thus trigger at the earliest
+ * possible time in the future.
+ *
+ * Note that this function will assume control over the event loop. Internally, it
+ * will actually `run()` the loop until the promise settles and then calls `stop()` to
+ * terminate execution of the loop. This means this function is more suited for
+ * short-lived promise executions when using promise-based APIs is not feasible.
+ * For long-running applications, using promise-based APIs by leveraging chained
+ * `then()` calls is usually preferable.
+ *
+ * @param PromiseInterface[] $promises
+ * @param ?LoopInterface $loop
+ * @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
+ * @return mixed returns whatever the first promise resolves to
+ * @throws Exception if ALL promises are rejected
+ * @throws TimeoutException if the $timeout is given and triggers
+ */
+function awaitAny(array $promises, LoopInterface $loop = null, $timeout = null)
+{
+ // Explicitly overwrite argument with null value. This ensure that this
+ // argument does not show up in the stack trace in PHP 7+ only.
+ $all = $promises;
+ $promises = null;
+
+ try {
+ // Promise\any() does not cope with an empty input array, so reject this here
+ if (!$all) {
+ throw new UnderflowException('Empty input array');
+ }
+
+ $ret = await(Promise\any($all)->then(null, function () {
+ // rejects with an array of rejection reasons => reject with Exception instead
+ throw new Exception('All promises rejected');
+ }), $loop, $timeout);
+ } catch (TimeoutException $e) {
+ // the timeout fired
+ // => try to cancel all promises (rejected ones will be ignored anyway)
+ _cancelAllPromises($all);
+
+ throw $e;
+ } catch (Exception $e) {
+ // if the above throws, then ALL promises are already rejected
+ // => try to cancel all promises (rejected ones will be ignored anyway)
+ _cancelAllPromises($all);
+
+ throw new UnderflowException('No promise could resolve', 0, $e);
+ }
+
+ // if we reach this, then ANY of the given promises resolved
+ // => try to cancel all promises (settled ones will be ignored anyway)
+ _cancelAllPromises($all);
+
+ return $ret;
+}
+
+/**
+ * Wait for ALL of the given promises to be fulfilled.
+ *
+ * ```php
+ * $promises = array(
+ * $promise1,
+ * $promise2
+ * );
+ *
+ * $allResults = Clue\React\Block\awaitAll($promises, $loop);
+ *
+ * echo 'First promise resolved with: ' . $allResults[0];
+ * ```
+ *
+ * See also the [examples](../examples/).
+ *
+ * This function will only return after ALL of the given `$promises` have been
+ * fulfilled or will throw when ANY of them have been rejected. In the meantime,
+ * the event loop will run any events attached to the same loop.
+ *
+ * Once ALL promises are fulfilled, this will return an array with whatever
+ * each promise resolves to. Array keys will be left intact, i.e. they can
+ * be used to correlate the return array to the promises passed.
+ *
+ * Once ANY promise rejects, this will try to `cancel()` all remaining promises
+ * and throw an `Exception`. If the promise did not reject with an `Exception`,
+ * then this function will throw an `UnexpectedValueException` instead.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * If no `$timeout` argument is given and ANY promises stay pending, then this
+ * will potentially wait/block forever until the promise is fulfilled. To avoid
+ * this, API authors creating promises are expected to provide means to
+ * configure a timeout for the promise instead. For more details, see also the
+ * [`timeout()` function](https://github.com/reactphp/promise-timer#timeout).
+ *
+ * If the deprecated `$timeout` argument is given and ANY promises are still pending once
+ * the timeout triggers, this will `cancel()` all pending promises and throw a
+ * `TimeoutException`. This implies that if you pass a really small (or negative)
+ * value, it will still start a timer and will thus trigger at the earliest
+ * possible time in the future.
+ *
+ * Note that this function will assume control over the event loop. Internally, it
+ * will actually `run()` the loop until the promise settles and then calls `stop()` to
+ * terminate execution of the loop. This means this function is more suited for
+ * short-lived promise executions when using promise-based APIs is not feasible.
+ * For long-running applications, using promise-based APIs by leveraging chained
+ * `then()` calls is usually preferable.
+ *
+ * @param PromiseInterface[] $promises
+ * @param ?LoopInterface $loop
+ * @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
+ * @return array returns an array with whatever each promise resolves to
+ * @throws Exception when ANY promise is rejected
+ * @throws TimeoutException if the $timeout is given and triggers
+ */
+function awaitAll(array $promises, LoopInterface $loop = null, $timeout = null)
+{
+ // Explicitly overwrite argument with null value. This ensure that this
+ // argument does not show up in the stack trace in PHP 7+ only.
+ $all = $promises;
+ $promises = null;
+
+ try {
+ return await(Promise\all($all), $loop, $timeout);
+ } catch (Exception $e) {
+ // ANY of the given promises rejected or the timeout fired
+ // => try to cancel all promises (rejected ones will be ignored anyway)
+ _cancelAllPromises($all);
+
+ throw $e;
+ }
+}
+
+/**
+ * internal helper function used to iterate over an array of Promise instances and cancel() each
+ *
+ * @internal
+ * @param array $promises
+ * @return void
+ */
+function _cancelAllPromises(array $promises)
+{
+ foreach ($promises as $promise) {
+ if ($promise instanceof PromiseInterface && ($promise instanceof CancellablePromiseInterface || !\interface_exists('React\Promise\CancellablePromiseInterface'))) {
+ $promise->cancel();
+ }
+ }
+}
diff --git a/vendor/clue/block-react/src/functions_include.php b/vendor/clue/block-react/src/functions_include.php
new file mode 100644
index 0000000..b3ad74c
--- /dev/null
+++ b/vendor/clue/block-react/src/functions_include.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Clue\React\Block;
+
+if (!function_exists('Clue\\React\\Block\\sleep')) {
+ require __DIR__ . '/functions.php';
+}
+
diff --git a/vendor/clue/buzz-react/LICENSE b/vendor/clue/buzz-react/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/buzz-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+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/clue/buzz-react/composer.json b/vendor/clue/buzz-react/composer.json
new file mode 100644
index 0000000..99e6d69
--- /dev/null
+++ b/vendor/clue/buzz-react/composer.json
@@ -0,0 +1,38 @@
+{
+ "name": "clue/buzz-react",
+ "description": "Simple, async PSR-7 HTTP client for concurrently processing any number of HTTP requests, built on top of ReactPHP",
+ "keywords": ["HTTP client", "PSR-7", "HTTP", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-buzz",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\Buzz\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Buzz\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/http-client": "^0.5.10",
+ "react/promise": "^2.2.1 || ^1.2.1",
+ "react/promise-stream": "^1.0 || ^0.1.2",
+ "react/socket": "^1.1",
+ "react/stream": "^1.0 || ^0.7",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "clue/http-proxy-react": "^1.3",
+ "clue/reactphp-ssh-proxy": "^1.0",
+ "clue/socks-react": "^1.0",
+ "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35",
+ "react/http": "^0.8"
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Browser.php b/vendor/clue/buzz-react/src/Browser.php
new file mode 100644
index 0000000..8f1a751
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Browser.php
@@ -0,0 +1,867 @@
+<?php
+
+namespace Clue\React\Buzz;
+
+use Clue\React\Buzz\Io\Sender;
+use Clue\React\Buzz\Io\Transaction;
+use Clue\React\Buzz\Message\MessageFactory;
+use InvalidArgumentException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\PromiseInterface;
+use React\Socket\ConnectorInterface;
+use React\Stream\ReadableStreamInterface;
+
+class Browser
+{
+ private $transaction;
+ private $messageFactory;
+ private $baseUrl;
+ private $protocolVersion = '1.1';
+
+ /**
+ * The `Browser` is responsible for sending HTTP requests to your HTTP server
+ * and keeps track of pending incoming HTTP responses.
+ * It also registers everything with the main [`EventLoop`](https://github.com/reactphp/event-loop#usage).
+ *
+ * ```php
+ * $loop = React\EventLoop\Factory::create();
+ *
+ * $browser = new Clue\React\Buzz\Browser($loop);
+ * ```
+ *
+ * If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
+ * proxy servers etc.), you can explicitly pass a custom instance of the
+ * [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface):
+ *
+ * ```php
+ * $connector = new React\Socket\Connector($loop, array(
+ * 'dns' => '127.0.0.1',
+ * 'tcp' => array(
+ * 'bindto' => '192.168.10.1:0'
+ * ),
+ * 'tls' => array(
+ * 'verify_peer' => false,
+ * 'verify_peer_name' => false
+ * )
+ * ));
+ *
+ * $browser = new Clue\React\Buzz\Browser($loop, $connector);
+ * ```
+ *
+ * @param LoopInterface $loop
+ * @param ConnectorInterface|null $connector [optional] Connector to use.
+ * Should be `null` in order to use default Connector.
+ */
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null)
+ {
+ $this->messageFactory = new MessageFactory();
+ $this->transaction = new Transaction(
+ Sender::createFromLoop($loop, $connector, $this->messageFactory),
+ $this->messageFactory,
+ $loop
+ );
+ }
+
+ /**
+ * Sends an HTTP GET request
+ *
+ * ```php
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * });
+ * ```
+ *
+ * See also [example 01](../examples/01-google.php).
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function get($url, array $headers = array())
+ {
+ return $this->requestMayBeStreaming('GET', $url, $headers);
+ }
+
+ /**
+ * Sends an HTTP POST request
+ *
+ * ```php
+ * $browser->post(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/json'
+ * ],
+ * json_encode($data)
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump(json_decode((string)$response->getBody()));
+ * });
+ * ```
+ *
+ * See also [example 04](../examples/04-post-json.php).
+ *
+ * This method is also commonly used to submit HTML form data:
+ *
+ * ```php
+ * $data = [
+ * 'user' => 'Alice',
+ * 'password' => 'secret'
+ * ];
+ *
+ * $browser->post(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/x-www-form-urlencoded'
+ * ],
+ * http_build_query($data)
+ * );
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * $loop->addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->post($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $contents
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function post($url, array $headers = array(), $contents = '')
+ {
+ return $this->requestMayBeStreaming('POST', $url, $headers, $contents);
+ }
+
+ /**
+ * Sends an HTTP HEAD request
+ *
+ * ```php
+ * $browser->head($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump($response->getHeaders());
+ * });
+ * ```
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function head($url, array $headers = array())
+ {
+ return $this->requestMayBeStreaming('HEAD', $url, $headers);
+ }
+
+ /**
+ * Sends an HTTP PATCH request
+ *
+ * ```php
+ * $browser->patch(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/json'
+ * ],
+ * json_encode($data)
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump(json_decode((string)$response->getBody()));
+ * });
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * $loop->addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->patch($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $contents
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function patch($url, array $headers = array(), $contents = '')
+ {
+ return $this->requestMayBeStreaming('PATCH', $url , $headers, $contents);
+ }
+
+ /**
+ * Sends an HTTP PUT request
+ *
+ * ```php
+ * $browser->put(
+ * $url,
+ * [
+ * 'Content-Type' => 'text/xml'
+ * ],
+ * $xml->asXML()
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * });
+ * ```
+ *
+ * See also [example 05](../examples/05-put-xml.php).
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * $loop->addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->put($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $contents
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function put($url, array $headers = array(), $contents = '')
+ {
+ return $this->requestMayBeStreaming('PUT', $url, $headers, $contents);
+ }
+
+ /**
+ * Sends an HTTP DELETE request
+ *
+ * ```php
+ * $browser->delete($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * });
+ * ```
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $contents
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function delete($url, array $headers = array(), $contents = '')
+ {
+ return $this->requestMayBeStreaming('DELETE', $url, $headers, $contents);
+ }
+
+ /**
+ * Sends an arbitrary HTTP request.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request.
+ *
+ * As an alternative, if you want to use a custom HTTP request method, you
+ * can use this method:
+ *
+ * ```php
+ * $browser->request('OPTIONS', $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * });
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the size of the outgoing request body is known and non-empty.
+ * For an empty request body, if will only include a `Content-Length: 0`
+ * request header if the request method usually expects a request body (only
+ * applies to `POST`, `PUT` and `PATCH`).
+ *
+ * If you're using a streaming request body (`ReadableStreamInterface`), it
+ * will default to using `Transfer-Encoding: chunked` or you have to
+ * explicitly pass in a matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * $loop->addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->request('POST', $url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * > Note that this method is available as of v2.9.0 and always buffers the
+ * response body before resolving.
+ * It does not respect the deprecated [`streaming` option](#withoptions).
+ * If you want to stream the response body, you can use the
+ * [`requestStreaming()`](#requeststreaming) method instead.
+ *
+ * @param string $method HTTP request method, e.g. GET/HEAD/POST etc.
+ * @param string $url URL for the request
+ * @param array $headers Additional request headers
+ * @param string|ReadableStreamInterface $body HTTP request body contents
+ * @return PromiseInterface<ResponseInterface,Exception>
+ * @since 2.9.0
+ */
+ public function request($method, $url, array $headers = array(), $body = '')
+ {
+ return $this->withOptions(array('streaming' => false))->requestMayBeStreaming($method, $url, $headers, $body);
+ }
+
+ /**
+ * Sends an arbitrary HTTP request and receives a streaming response without buffering the response body.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request. Each of these methods will buffer
+ * the whole response body in memory by default. This is easy to get started
+ * and works reasonably well for smaller responses.
+ *
+ * In some situations, it's a better idea to use a streaming approach, where
+ * only small chunks have to be kept in memory. You can use this method to
+ * send an arbitrary HTTP request and receive a streaming response. It uses
+ * the same HTTP message API, but does not buffer the response body in
+ * memory. It only processes the response body in small chunks as data is
+ * received and forwards this data through [ReactPHP's Stream API](https://github.com/reactphp/stream).
+ * This works for (any number of) responses of arbitrary sizes.
+ *
+ * ```php
+ * $browser->requestStreaming('GET', $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * $body = $response->getBody();
+ * assert($body instanceof Psr\Http\Message\StreamInterface);
+ * assert($body instanceof React\Stream\ReadableStreamInterface);
+ *
+ * $body->on('data', function ($chunk) {
+ * echo $chunk;
+ * });
+ *
+ * $body->on('error', function (Exception $error) {
+ * echo 'Error: ' . $error->getMessage() . PHP_EOL;
+ * });
+ *
+ * $body->on('close', function () {
+ * echo '[DONE]' . PHP_EOL;
+ * });
+ * });
+ * ```
+ *
+ * See also [`ReadableStreamInterface`](https://github.com/reactphp/stream#readablestreaminterface)
+ * and the [streaming response](#streaming-response) for more details,
+ * examples and possible use-cases.
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the size of the outgoing request body is known and non-empty.
+ * For an empty request body, if will only include a `Content-Length: 0`
+ * request header if the request method usually expects a request body (only
+ * applies to `POST`, `PUT` and `PATCH`).
+ *
+ * If you're using a streaming request body (`ReadableStreamInterface`), it
+ * will default to using `Transfer-Encoding: chunked` or you have to
+ * explicitly pass in a matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * $loop->addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->requestStreaming('POST', $url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * > Note that this method is available as of v2.9.0 and always resolves the
+ * response without buffering the response body.
+ * It does not respect the deprecated [`streaming` option](#withoptions).
+ * If you want to buffer the response body, use can use the
+ * [`request()`](#request) method instead.
+ *
+ * @param string $method HTTP request method, e.g. GET/HEAD/POST etc.
+ * @param string $url URL for the request
+ * @param array $headers Additional request headers
+ * @param string|ReadableStreamInterface $body HTTP request body contents
+ * @return PromiseInterface<ResponseInterface,Exception>
+ * @since 2.9.0
+ */
+ public function requestStreaming($method, $url, $headers = array(), $contents = '')
+ {
+ return $this->withOptions(array('streaming' => true))->requestMayBeStreaming($method, $url, $headers, $contents);
+ }
+
+ /**
+ * [Deprecated] Submits an array of field values similar to submitting a form (`application/x-www-form-urlencoded`).
+ *
+ * ```php
+ * // deprecated: see post() instead
+ * $browser->submit($url, array('user' => 'test', 'password' => 'secret'));
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header for the encoded length of the given `$fields`.
+ *
+ * > For BC reasons, this method accepts the `$url` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * @param string|UriInterface $url URL for the request.
+ * @param array $fields
+ * @param array $headers
+ * @param string $method
+ * @return PromiseInterface<ResponseInterface>
+ * @deprecated 2.9.0 See self::post() instead.
+ * @see self::post()
+ */
+ public function submit($url, array $fields, $headers = array(), $method = 'POST')
+ {
+ $headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ $contents = http_build_query($fields);
+
+ return $this->requestMayBeStreaming($method, $url, $headers, $contents);
+ }
+
+ /**
+ * [Deprecated] Sends an arbitrary instance implementing the [`RequestInterface`](#requestinterface) (PSR-7).
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request.
+ *
+ * As an alternative, if you want to use a custom HTTP request method, you
+ * can use this method:
+ *
+ * ```php
+ * $request = new Request('OPTIONS', $url);
+ *
+ * // deprecated: see request() instead
+ * $browser->send($request)->then(…);
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the size of the outgoing request body is known and non-empty.
+ * For an empty request body, if will only include a `Content-Length: 0`
+ * request header if the request method usually expects a request body (only
+ * applies to `POST`, `PUT` and `PATCH`).
+ *
+ * @param RequestInterface $request
+ * @return PromiseInterface<ResponseInterface>
+ * @deprecated 2.9.0 See self::request() instead.
+ * @see self::request()
+ */
+ public function send(RequestInterface $request)
+ {
+ if ($this->baseUrl !== null) {
+ // ensure we're actually below the base URL
+ $request = $request->withUri($this->messageFactory->expandBase($request->getUri(), $this->baseUrl));
+ }
+
+ return $this->transaction->send($request);
+ }
+
+ /**
+ * Changes the maximum timeout used for waiting for pending requests.
+ *
+ * You can pass in the number of seconds to use as a new timeout value:
+ *
+ * ```php
+ * $browser = $browser->withTimeout(10.0);
+ * ```
+ *
+ * You can pass in a bool `false` to disable any timeouts. In this case,
+ * requests can stay pending forever:
+ *
+ * ```php
+ * $browser = $browser->withTimeout(false);
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default timeout handling. This
+ * will respects PHP's `default_socket_timeout` setting (default 60s):
+ *
+ * ```php
+ * $browser = $browser->withTimeout(true);
+ * ```
+ *
+ * See also [timeouts](#timeouts) for more details about timeout handling.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given timeout value applied.
+ *
+ * @param bool|number $timeout
+ * @return self
+ */
+ public function withTimeout($timeout)
+ {
+ if ($timeout === true) {
+ $timeout = null;
+ } elseif ($timeout === false) {
+ $timeout = -1;
+ } elseif ($timeout < 0) {
+ $timeout = 0;
+ }
+
+ return $this->withOptions(array(
+ 'timeout' => $timeout,
+ ));
+ }
+
+ /**
+ * Changes how HTTP redirects will be followed.
+ *
+ * You can pass in the maximum number of redirects to follow:
+ *
+ * ```php
+ * $new = $browser->withFollowRedirects(5);
+ * ```
+ *
+ * The request will automatically be rejected when the number of redirects
+ * is exceeded. You can pass in a `0` to reject the request for any
+ * redirects encountered:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(0);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // only non-redirected responses will now end up here
+ * var_dump($response->getHeaders());
+ * });
+ * ```
+ *
+ * You can pass in a bool `false` to disable following any redirects. In
+ * this case, requests will resolve with the redirection response instead
+ * of following the `Location` response header:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(false);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any redirects will now end up here
+ * var_dump($response->getHeaderLine('Location'));
+ * });
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default redirect handling.
+ * This defaults to following a maximum of 10 redirects:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(true);
+ * ```
+ *
+ * See also [redirects](#redirects) for more details about redirect handling.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given redirect setting applied.
+ *
+ * @param bool|int $followRedirects
+ * @return self
+ */
+ public function withFollowRedirects($followRedirects)
+ {
+ return $this->withOptions(array(
+ 'followRedirects' => $followRedirects !== false,
+ 'maxRedirects' => \is_bool($followRedirects) ? null : $followRedirects
+ ));
+ }
+
+ /**
+ * Changes whether non-successful HTTP response status codes (4xx and 5xx) will be rejected.
+ *
+ * You can pass in a bool `false` to disable rejecting incoming responses
+ * that use a 4xx or 5xx response status code. In this case, requests will
+ * resolve with the response message indicating an error condition:
+ *
+ * ```php
+ * $browser = $browser->withRejectErrorResponse(false);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any HTTP response will now end up here
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * });
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default status code handling.
+ * This defaults to rejecting any response status codes in the 4xx or 5xx
+ * range:
+ *
+ * ```php
+ * $browser = $browser->withRejectErrorResponse(true);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any successful HTTP response will now end up here
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * }, function (Exception $e) {
+ * if ($e instanceof Clue\React\Buzz\Message\ResponseException) {
+ * // any HTTP response error message will now end up here
+ * $response = $e->getResponse();
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * } else {
+ * var_dump($e->getMessage());
+ * }
+ * });
+ * ```
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given setting applied.
+ *
+ * @param bool $obeySuccessCode
+ * @return self
+ */
+ public function withRejectErrorResponse($obeySuccessCode)
+ {
+ return $this->withOptions(array(
+ 'obeySuccessCode' => $obeySuccessCode,
+ ));
+ }
+
+ /**
+ * Changes the base URL used to resolve relative URLs to.
+ *
+ * If you configure a base URL, any requests to relative URLs will be
+ * processed by first prepending this absolute base URL. Note that this
+ * merely prepends the base URL and does *not* resolve any relative path
+ * references (like `../` etc.). This is mostly useful for (RESTful) API
+ * calls where all endpoints (URLs) are located under a common base URL.
+ *
+ * ```php
+ * $browser = $browser->withBase('http://api.example.com/v3');
+ *
+ * // will request http://api.example.com/v3/example
+ * $browser->get('/example')->then(…);
+ * ```
+ *
+ * You can pass in a `null` base URL to return a new instance that does not
+ * use a base URL:
+ *
+ * ```php
+ * $browser = $browser->withBase(null);
+ * ```
+ *
+ * Accordingly, any requests using relative URLs to a browser that does not
+ * use a base URL can not be completed and will be rejected without sending
+ * a request.
+ *
+ * This method will throw an `InvalidArgumentException` if the given
+ * `$baseUrl` argument is not a valid URL.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withBase()` method
+ * actually returns a *new* [`Browser`](#browser) instance with the given base URL applied.
+ *
+ * > For BC reasons, this method accepts the `$baseUrl` as either a `string`
+ * value or as an `UriInterface`. It's recommended to explicitly cast any
+ * objects implementing `UriInterface` to `string`.
+ *
+ * > Changelog: As of v2.9.0 this method accepts a `null` value to reset the
+ * base URL. Earlier versions had to use the deprecated `withoutBase()`
+ * method to reset the base URL.
+ *
+ * @param string|null|UriInterface $baseUrl absolute base URL
+ * @return self
+ * @throws InvalidArgumentException if the given $baseUrl is not a valid absolute URL
+ * @see self::withoutBase()
+ */
+ public function withBase($baseUrl)
+ {
+ $browser = clone $this;
+ if ($baseUrl === null) {
+ $browser->baseUrl = null;
+ return $browser;
+ }
+
+ $browser->baseUrl = $this->messageFactory->uri($baseUrl);
+ if (!\in_array($browser->baseUrl->getScheme(), array('http', 'https')) || $browser->baseUrl->getHost() === '') {
+ throw new \InvalidArgumentException('Base URL must be absolute');
+ }
+
+ return $browser;
+ }
+
+ /**
+ * Changes the HTTP protocol version that will be used for all subsequent requests.
+ *
+ * All the above [request methods](#request-methods) default to sending
+ * requests as HTTP/1.1. This is the preferred HTTP protocol version which
+ * also provides decent backwards-compatibility with legacy HTTP/1.0
+ * servers. As such, there should rarely be a need to explicitly change this
+ * protocol version.
+ *
+ * If you want to explicitly use the legacy HTTP/1.0 protocol version, you
+ * can use this method:
+ *
+ * ```php
+ * $newBrowser = $browser->withProtocolVersion('1.0');
+ *
+ * $newBrowser->get($url)->then(…);
+ * ```
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * new protocol version applied.
+ *
+ * @param string $protocolVersion HTTP protocol version to use, must be one of "1.1" or "1.0"
+ * @return self
+ * @throws InvalidArgumentException
+ * @since 2.8.0
+ */
+ public function withProtocolVersion($protocolVersion)
+ {
+ if (!\in_array($protocolVersion, array('1.0', '1.1'), true)) {
+ throw new InvalidArgumentException('Invalid HTTP protocol version, must be one of "1.1" or "1.0"');
+ }
+
+ $browser = clone $this;
+ $browser->protocolVersion = (string) $protocolVersion;
+
+ return $browser;
+ }
+
+ /**
+ * Changes the maximum size for buffering a response body.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request. Each of these methods will buffer
+ * the whole response body in memory by default. This is easy to get started
+ * and works reasonably well for smaller responses.
+ *
+ * By default, the response body buffer will be limited to 16 MiB. If the
+ * response body exceeds this maximum size, the request will be rejected.
+ *
+ * You can pass in the maximum number of bytes to buffer:
+ *
+ * ```php
+ * $browser = $browser->withResponseBuffer(1024 * 1024);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // response body will not exceed 1 MiB
+ * var_dump($response->getHeaders(), (string) $response->getBody());
+ * });
+ * ```
+ *
+ * Note that the response body buffer has to be kept in memory for each
+ * pending request until its transfer is completed and it will only be freed
+ * after a pending request is fulfilled. As such, increasing this maximum
+ * buffer size to allow larger response bodies is usually not recommended.
+ * Instead, you can use the [`requestStreaming()` method](#requeststreaming)
+ * to receive responses with arbitrary sizes without buffering. Accordingly,
+ * this maximum buffer size setting has no effect on streaming responses.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given setting applied.
+ *
+ * @param int $maximumSize
+ * @return self
+ * @see self::requestStreaming()
+ */
+ public function withResponseBuffer($maximumSize)
+ {
+ return $this->withOptions(array(
+ 'maximumSize' => $maximumSize
+ ));
+ }
+
+ /**
+ * [Deprecated] Changes the [options](#options) to use:
+ *
+ * The [`Browser`](#browser) class exposes several options for the handling of
+ * HTTP transactions. These options resemble some of PHP's
+ * [HTTP context options](http://php.net/manual/en/context.http.php) and
+ * can be controlled via the following API (and their defaults):
+ *
+ * ```php
+ * // deprecated
+ * $newBrowser = $browser->withOptions(array(
+ * 'timeout' => null, // see withTimeout() instead
+ * 'followRedirects' => true, // see withFollowRedirects() instead
+ * 'maxRedirects' => 10, // see withFollowRedirects() instead
+ * 'obeySuccessCode' => true, // see withRejectErrorResponse() instead
+ * 'streaming' => false, // deprecated, see requestStreaming() instead
+ * ));
+ * ```
+ *
+ * See also [timeouts](#timeouts), [redirects](#redirects) and
+ * [streaming](#streaming) for more details.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * options applied.
+ *
+ * @param array $options
+ * @return self
+ * @deprecated 2.9.0 See self::withTimeout(), self::withFollowRedirects() and self::withRejectErrorResponse() instead.
+ * @see self::withTimeout()
+ * @see self::withFollowRedirects()
+ * @see self::withRejectErrorResponse()
+ */
+ public function withOptions(array $options)
+ {
+ $browser = clone $this;
+ $browser->transaction = $this->transaction->withOptions($options);
+
+ return $browser;
+ }
+
+ /**
+ * [Deprecated] Removes the base URL.
+ *
+ * ```php
+ * // deprecated: see withBase() instead
+ * $newBrowser = $browser->withoutBase();
+ * ```
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withoutBase()` method
+ * actually returns a *new* [`Browser`](#browser) instance without any base URL applied.
+ *
+ * See also [`withBase()`](#withbase).
+ *
+ * @return self
+ * @deprecated 2.9.0 See self::withBase() instead.
+ * @see self::withBase()
+ */
+ public function withoutBase()
+ {
+ return $this->withBase(null);
+ }
+
+ /**
+ * @param string $method
+ * @param string|UriInterface $url
+ * @param array $headers
+ * @param string|ReadableStreamInterface $contents
+ * @return PromiseInterface<ResponseInterface,Exception>
+ */
+ private function requestMayBeStreaming($method, $url, array $headers = array(), $contents = '')
+ {
+ return $this->send($this->messageFactory->request($method, $url, $headers, $contents, $this->protocolVersion));
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Io/ChunkedEncoder.php b/vendor/clue/buzz-react/src/Io/ChunkedEncoder.php
new file mode 100644
index 0000000..3b74e0c
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Io/ChunkedEncoder.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Clue\React\Buzz\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Encodes given payload stream with "Transfer-Encoding: chunked" and emits encoded data
+ *
+ * This is used internally to encode outgoing requests with this encoding.
+ *
+ * @internal
+ * @link https://github.com/reactphp/http/blob/master/src/Io/ChunkedEncoder.php Originally from react/http
+ */
+class ChunkedEncoder extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ if ($data !== '') {
+ $this->emit('data', array(
+ dechex(strlen($data)) . "\r\n" . $data . "\r\n"
+ ));
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->emit('data', array("0\r\n\r\n"));
+
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Io/Sender.php b/vendor/clue/buzz-react/src/Io/Sender.php
new file mode 100644
index 0000000..06c1212
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Io/Sender.php
@@ -0,0 +1,161 @@
+<?php
+
+namespace Clue\React\Buzz\Io;
+
+use Clue\React\Buzz\Message\MessageFactory;
+use Psr\Http\Message\RequestInterface;
+use React\EventLoop\LoopInterface;
+use React\HttpClient\Client as HttpClient;
+use React\HttpClient\Response as ResponseStream;
+use React\Promise\PromiseInterface;
+use React\Promise\Deferred;
+use React\Socket\ConnectorInterface;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * [Internal] Sends requests and receives responses
+ *
+ * The `Sender` is responsible for passing the [`RequestInterface`](#requestinterface) objects to
+ * the underlying [`HttpClient`](https://github.com/reactphp/http-client) library
+ * and keeps track of its transmission and converts its reponses back to [`ResponseInterface`](#responseinterface) objects.
+ *
+ * It also registers everything with the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
+ * and the default [`Connector`](https://github.com/reactphp/socket-client) and [DNS `Resolver`](https://github.com/reactphp/dns).
+ *
+ * The `Sender` class mostly exists in order to abstract changes on the underlying
+ * components away from this package in order to provide backwards and forwards
+ * compatibility.
+ *
+ * @internal You SHOULD NOT rely on this API, it is subject to change without prior notice!
+ * @see Browser
+ */
+class Sender
+{
+ /**
+ * create a new default sender attached to the given event loop
+ *
+ * This method is used internally to create the "default sender".
+ *
+ * You may also use this method if you need custom DNS or connector
+ * settings. You can use this method manually like this:
+ *
+ * ```php
+ * $connector = new \React\Socket\Connector($loop);
+ * $sender = \Clue\React\Buzz\Io\Sender::createFromLoop($loop, $connector);
+ * ```
+ *
+ * @param LoopInterface $loop
+ * @param ConnectorInterface|null $connector
+ * @return self
+ */
+ public static function createFromLoop(LoopInterface $loop, ConnectorInterface $connector = null, MessageFactory $messageFactory)
+ {
+ return new self(new HttpClient($loop, $connector), $messageFactory);
+ }
+
+ private $http;
+ private $messageFactory;
+
+ /**
+ * [internal] Instantiate Sender
+ *
+ * @param HttpClient $http
+ * @internal
+ */
+ public function __construct(HttpClient $http, MessageFactory $messageFactory)
+ {
+ $this->http = $http;
+ $this->messageFactory = $messageFactory;
+ }
+
+ /**
+ *
+ * @internal
+ * @param RequestInterface $request
+ * @return PromiseInterface Promise<ResponseInterface, Exception>
+ */
+ public function send(RequestInterface $request)
+ {
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ if ($size !== null && $size !== 0) {
+ // automatically assign a "Content-Length" request header if the body size is known and non-empty
+ $request = $request->withHeader('Content-Length', (string)$size);
+ } elseif ($size === 0 && \in_array($request->getMethod(), array('POST', 'PUT', 'PATCH'))) {
+ // only assign a "Content-Length: 0" request header if the body is expected for certain methods
+ $request = $request->withHeader('Content-Length', '0');
+ } elseif ($body instanceof ReadableStreamInterface && $body->isReadable() && !$request->hasHeader('Content-Length')) {
+ // use "Transfer-Encoding: chunked" when this is a streaming body and body size is unknown
+ $request = $request->withHeader('Transfer-Encoding', 'chunked');
+ } else {
+ // do not use chunked encoding if size is known or if this is an empty request body
+ $size = 0;
+ }
+
+ $headers = array();
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[$name] = implode(', ', $values);
+ }
+
+ $requestStream = $this->http->request($request->getMethod(), (string)$request->getUri(), $headers, $request->getProtocolVersion());
+
+ $deferred = new Deferred(function ($_, $reject) use ($requestStream) {
+ // close request stream if request is cancelled
+ $reject(new \RuntimeException('Request cancelled'));
+ $requestStream->close();
+ });
+
+ $requestStream->on('error', function($error) use ($deferred) {
+ $deferred->reject($error);
+ });
+
+ $messageFactory = $this->messageFactory;
+ $requestStream->on('response', function (ResponseStream $responseStream) use ($deferred, $messageFactory, $request) {
+ // apply response header values from response stream
+ $deferred->resolve($messageFactory->response(
+ $responseStream->getVersion(),
+ $responseStream->getCode(),
+ $responseStream->getReasonPhrase(),
+ $responseStream->getHeaders(),
+ $responseStream,
+ $request->getMethod()
+ ));
+ });
+
+ if ($body instanceof ReadableStreamInterface) {
+ if ($body->isReadable()) {
+ // length unknown => apply chunked transfer-encoding
+ if ($size === null) {
+ $body = new ChunkedEncoder($body);
+ }
+
+ // pipe body into request stream
+ // add dummy write to immediately start request even if body does not emit any data yet
+ $body->pipe($requestStream);
+ $requestStream->write('');
+
+ $body->on('close', $close = function () use ($deferred, $requestStream) {
+ $deferred->reject(new \RuntimeException('Request failed because request body closed unexpectedly'));
+ $requestStream->close();
+ });
+ $body->on('error', function ($e) use ($deferred, $requestStream, $close, $body) {
+ $body->removeListener('close', $close);
+ $deferred->reject(new \RuntimeException('Request failed because request body reported an error', 0, $e));
+ $requestStream->close();
+ });
+ $body->on('end', function () use ($close, $body) {
+ $body->removeListener('close', $close);
+ });
+ } else {
+ // stream is not readable => end request without body
+ $requestStream->end();
+ }
+ } else {
+ // body is fully buffered => write as one chunk
+ $requestStream->end((string)$body);
+ }
+
+ return $deferred->promise();
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Io/Transaction.php b/vendor/clue/buzz-react/src/Io/Transaction.php
new file mode 100644
index 0000000..adb5796
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Io/Transaction.php
@@ -0,0 +1,305 @@
+<?php
+
+namespace Clue\React\Buzz\Io;
+
+use Clue\React\Buzz\Message\ResponseException;
+use Clue\React\Buzz\Message\MessageFactory;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * @internal
+ */
+class Transaction
+{
+ private $sender;
+ private $messageFactory;
+ private $loop;
+
+ // context: http.timeout (ini_get('default_socket_timeout'): 60)
+ private $timeout;
+
+ // context: http.follow_location (true)
+ private $followRedirects = true;
+
+ // context: http.max_redirects (10)
+ private $maxRedirects = 10;
+
+ // context: http.ignore_errors (false)
+ private $obeySuccessCode = true;
+
+ private $streaming = false;
+
+ private $maximumSize = 16777216; // 16 MiB = 2^24 bytes
+
+ public function __construct(Sender $sender, MessageFactory $messageFactory, LoopInterface $loop)
+ {
+ $this->sender = $sender;
+ $this->messageFactory = $messageFactory;
+ $this->loop = $loop;
+ }
+
+ /**
+ * @param array $options
+ * @return self returns new instance, without modifying existing instance
+ */
+ public function withOptions(array $options)
+ {
+ $transaction = clone $this;
+ foreach ($options as $name => $value) {
+ if (property_exists($transaction, $name)) {
+ // restore default value if null is given
+ if ($value === null) {
+ $default = new self($this->sender, $this->messageFactory, $this->loop);
+ $value = $default->$name;
+ }
+
+ $transaction->$name = $value;
+ }
+ }
+
+ return $transaction;
+ }
+
+ public function send(RequestInterface $request)
+ {
+ $deferred = new Deferred(function () use (&$deferred) {
+ if (isset($deferred->pending)) {
+ $deferred->pending->cancel();
+ unset($deferred->pending);
+ }
+ });
+
+ $deferred->numRequests = 0;
+
+ // use timeout from options or default to PHP's default_socket_timeout (60)
+ $timeout = (float)($this->timeout !== null ? $this->timeout : ini_get("default_socket_timeout"));
+
+ $loop = $this->loop;
+ $this->next($request, $deferred)->then(
+ function (ResponseInterface $response) use ($deferred, $loop, &$timeout) {
+ if (isset($deferred->timeout)) {
+ $loop->cancelTimer($deferred->timeout);
+ unset($deferred->timeout);
+ }
+ $timeout = -1;
+ $deferred->resolve($response);
+ },
+ function ($e) use ($deferred, $loop, &$timeout) {
+ if (isset($deferred->timeout)) {
+ $loop->cancelTimer($deferred->timeout);
+ unset($deferred->timeout);
+ }
+ $timeout = -1;
+ $deferred->reject($e);
+ }
+ );
+
+ if ($timeout < 0) {
+ return $deferred->promise();
+ }
+
+ $body = $request->getBody();
+ if ($body instanceof ReadableStreamInterface && $body->isReadable()) {
+ $that = $this;
+ $body->on('close', function () use ($that, $deferred, &$timeout) {
+ if ($timeout >= 0) {
+ $that->applyTimeout($deferred, $timeout);
+ }
+ });
+ } else {
+ $this->applyTimeout($deferred, $timeout);
+ }
+
+ return $deferred->promise();
+ }
+
+ /**
+ * @internal
+ * @param Deferred $deferred
+ * @param number $timeout
+ * @return void
+ */
+ public function applyTimeout(Deferred $deferred, $timeout)
+ {
+ $deferred->timeout = $this->loop->addTimer($timeout, function () use ($timeout, $deferred) {
+ $deferred->reject(new \RuntimeException(
+ 'Request timed out after ' . $timeout . ' seconds'
+ ));
+ if (isset($deferred->pending)) {
+ $deferred->pending->cancel();
+ unset($deferred->pending);
+ }
+ });
+ }
+
+ private function next(RequestInterface $request, Deferred $deferred)
+ {
+ $this->progress('request', array($request));
+
+ $that = $this;
+ ++$deferred->numRequests;
+
+ $promise = $this->sender->send($request);
+
+ if (!$this->streaming) {
+ $promise = $promise->then(function ($response) use ($deferred, $that) {
+ return $that->bufferResponse($response, $deferred);
+ });
+ }
+
+ $deferred->pending = $promise;
+
+ return $promise->then(
+ function (ResponseInterface $response) use ($request, $that, $deferred) {
+ return $that->onResponse($response, $request, $deferred);
+ }
+ );
+ }
+
+ /**
+ * @internal
+ * @param ResponseInterface $response
+ * @return PromiseInterface Promise<ResponseInterface, Exception>
+ */
+ public function bufferResponse(ResponseInterface $response, $deferred)
+ {
+ $stream = $response->getBody();
+
+ $size = $stream->getSize();
+ if ($size !== null && $size > $this->maximumSize) {
+ $stream->close();
+ return \React\Promise\reject(new \OverflowException(
+ 'Response body size of ' . $size . ' bytes exceeds maximum of ' . $this->maximumSize . ' bytes',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 0
+ ));
+ }
+
+ // body is not streaming => already buffered
+ if (!$stream instanceof ReadableStreamInterface) {
+ return \React\Promise\resolve($response);
+ }
+
+ // buffer stream and resolve with buffered body
+ $messageFactory = $this->messageFactory;
+ $maximumSize = $this->maximumSize;
+ $promise = \React\Promise\Stream\buffer($stream, $maximumSize)->then(
+ function ($body) use ($response, $messageFactory) {
+ return $response->withBody($messageFactory->body($body));
+ },
+ function ($e) use ($stream, $maximumSize) {
+ // try to close stream if buffering fails (or is cancelled)
+ $stream->close();
+
+ if ($e instanceof \OverflowException) {
+ $e = new \OverflowException(
+ 'Response body size exceeds maximum of ' . $maximumSize . ' bytes',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 0
+ );
+ }
+
+ throw $e;
+ }
+ );
+
+ $deferred->pending = $promise;
+
+ return $promise;
+ }
+
+ /**
+ * @internal
+ * @param ResponseInterface $response
+ * @param RequestInterface $request
+ * @throws ResponseException
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function onResponse(ResponseInterface $response, RequestInterface $request, $deferred)
+ {
+ $this->progress('response', array($response, $request));
+
+ // follow 3xx (Redirection) response status codes if Location header is present and not explicitly disabled
+ // @link https://tools.ietf.org/html/rfc7231#section-6.4
+ if ($this->followRedirects && ($response->getStatusCode() >= 300 && $response->getStatusCode() < 400) && $response->hasHeader('Location')) {
+ return $this->onResponseRedirect($response, $request, $deferred);
+ }
+
+ // only status codes 200-399 are considered to be valid, reject otherwise
+ if ($this->obeySuccessCode && ($response->getStatusCode() < 200 || $response->getStatusCode() >= 400)) {
+ throw new ResponseException($response);
+ }
+
+ // resolve our initial promise
+ return $response;
+ }
+
+ /**
+ * @param ResponseInterface $response
+ * @param RequestInterface $request
+ * @return PromiseInterface
+ * @throws \RuntimeException
+ */
+ private function onResponseRedirect(ResponseInterface $response, RequestInterface $request, Deferred $deferred)
+ {
+ // resolve location relative to last request URI
+ $location = $this->messageFactory->uriRelative($request->getUri(), $response->getHeaderLine('Location'));
+
+ $request = $this->makeRedirectRequest($request, $location);
+ $this->progress('redirect', array($request));
+
+ if ($deferred->numRequests >= $this->maxRedirects) {
+ throw new \RuntimeException('Maximum number of redirects (' . $this->maxRedirects . ') exceeded');
+ }
+
+ return $this->next($request, $deferred);
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param UriInterface $location
+ * @return RequestInterface
+ */
+ private function makeRedirectRequest(RequestInterface $request, UriInterface $location)
+ {
+ $originalHost = $request->getUri()->getHost();
+ $request = $request
+ ->withoutHeader('Host')
+ ->withoutHeader('Content-Type')
+ ->withoutHeader('Content-Length');
+
+ // Remove authorization if changing hostnames (but not if just changing ports or protocols).
+ if ($location->getHost() !== $originalHost) {
+ $request = $request->withoutHeader('Authorization');
+ }
+
+ // naïve approach..
+ $method = ($request->getMethod() === 'HEAD') ? 'HEAD' : 'GET';
+
+ return $this->messageFactory->request($method, $location, $request->getHeaders());
+ }
+
+ private function progress($name, array $args = array())
+ {
+ return;
+
+ echo $name;
+
+ foreach ($args as $arg) {
+ echo ' ';
+ if ($arg instanceof ResponseInterface) {
+ echo 'HTTP/' . $arg->getProtocolVersion() . ' ' . $arg->getStatusCode() . ' ' . $arg->getReasonPhrase();
+ } elseif ($arg instanceof RequestInterface) {
+ echo $arg->getMethod() . ' ' . $arg->getRequestTarget() . ' HTTP/' . $arg->getProtocolVersion();
+ } else {
+ echo $arg;
+ }
+ }
+
+ echo PHP_EOL;
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Message/MessageFactory.php b/vendor/clue/buzz-react/src/Message/MessageFactory.php
new file mode 100644
index 0000000..8a3dd6d
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Message/MessageFactory.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace Clue\React\Buzz\Message;
+
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+use RingCentral\Psr7\Request;
+use RingCentral\Psr7\Response;
+use RingCentral\Psr7\Uri;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * @internal
+ */
+class MessageFactory
+{
+ /**
+ * Creates a new instance of RequestInterface for the given request parameters
+ *
+ * @param string $method
+ * @param string|UriInterface $uri
+ * @param array $headers
+ * @param string|ReadableStreamInterface $content
+ * @param string $protocolVersion
+ * @return Request
+ */
+ public function request($method, $uri, $headers = array(), $content = '', $protocolVersion = '1.1')
+ {
+ return new Request($method, $uri, $headers, $this->body($content), $protocolVersion);
+ }
+
+ /**
+ * Creates a new instance of ResponseInterface for the given response parameters
+ *
+ * @param string $protocolVersion
+ * @param int $status
+ * @param string $reason
+ * @param array $headers
+ * @param ReadableStreamInterface|string $body
+ * @param ?string $requestMethod
+ * @return Response
+ * @uses self::body()
+ */
+ public function response($protocolVersion, $status, $reason, $headers = array(), $body = '', $requestMethod = null)
+ {
+ $response = new Response($status, $headers, $body instanceof ReadableStreamInterface ? null : $body, $protocolVersion, $reason);
+
+ if ($body instanceof ReadableStreamInterface) {
+ $length = null;
+ $code = $response->getStatusCode();
+ if ($requestMethod === 'HEAD' || ($code >= 100 && $code < 200) || $code == 204 || $code == 304) {
+ $length = 0;
+ } elseif (\strtolower($response->getHeaderLine('Transfer-Encoding')) === 'chunked') {
+ $length = null;
+ } elseif ($response->hasHeader('Content-Length')) {
+ $length = (int)$response->getHeaderLine('Content-Length');
+ }
+
+ $response = $response->withBody(new ReadableBodyStream($body, $length));
+ }
+
+ return $response;
+ }
+
+ /**
+ * Creates a new instance of StreamInterface for the given body contents
+ *
+ * @param ReadableStreamInterface|string $body
+ * @return StreamInterface
+ */
+ public function body($body)
+ {
+ if ($body instanceof ReadableStreamInterface) {
+ return new ReadableBodyStream($body);
+ }
+
+ return \RingCentral\Psr7\stream_for($body);
+ }
+
+ /**
+ * Creates a new instance of UriInterface for the given URI string
+ *
+ * @param string $uri
+ * @return UriInterface
+ */
+ public function uri($uri)
+ {
+ return new Uri($uri);
+ }
+
+ /**
+ * Creates a new instance of UriInterface for the given URI string relative to the given base URI
+ *
+ * @param UriInterface $base
+ * @param string $uri
+ * @return UriInterface
+ */
+ public function uriRelative(UriInterface $base, $uri)
+ {
+ return Uri::resolve($base, $uri);
+ }
+
+ /**
+ * Resolves the given relative or absolute $uri by appending it behind $this base URI
+ *
+ * The given $uri parameter can be either a relative or absolute URI and
+ * as such can not contain any URI template placeholders.
+ *
+ * As such, the outcome of this method represents a valid, absolute URI
+ * which will be returned as an instance implementing `UriInterface`.
+ *
+ * If the given $uri is a relative URI, it will simply be appended behind $base URI.
+ *
+ * If the given $uri is an absolute URI, it will simply be returned as-is.
+ *
+ * @param UriInterface $uri
+ * @param UriInterface $base
+ * @return UriInterface
+ */
+ public function expandBase(UriInterface $uri, UriInterface $base)
+ {
+ if ($uri->getScheme() !== '') {
+ return $uri;
+ }
+
+ $uri = (string)$uri;
+ $base = (string)$base;
+
+ if ($uri !== '' && substr($base, -1) !== '/' && substr($uri, 0, 1) !== '?') {
+ $base .= '/';
+ }
+
+ if (isset($uri[0]) && $uri[0] === '/') {
+ $uri = substr($uri, 1);
+ }
+
+ return $this->uri($base . $uri);
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Message/ReadableBodyStream.php b/vendor/clue/buzz-react/src/Message/ReadableBodyStream.php
new file mode 100644
index 0000000..eac27f7
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Message/ReadableBodyStream.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace Clue\React\Buzz\Message;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\StreamInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @internal
+ */
+class ReadableBodyStream extends EventEmitter implements ReadableStreamInterface, StreamInterface
+{
+ private $input;
+ private $position = 0;
+ private $size;
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $input, $size = null)
+ {
+ $this->input = $input;
+ $this->size = $size;
+
+ $that = $this;
+ $pos =& $this->position;
+ $input->on('data', function ($data) use ($that, &$pos, $size) {
+ $that->emit('data', array($data));
+
+ $pos += \strlen($data);
+ if ($size !== null && $pos >= $size) {
+ $that->handleEnd();
+ }
+ });
+ $input->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error));
+ $that->close();
+ });
+ $input->on('end', array($that, 'handleEnd'));
+ $input->on('close', array($that, 'close'));
+ }
+
+ public function close()
+ {
+ if (!$this->closed) {
+ $this->closed = true;
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+ }
+
+ public function isReadable()
+ {
+ return $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function eof()
+ {
+ return !$this->isReadable();
+ }
+
+ public function __toString()
+ {
+ return '';
+ }
+
+ public function detach()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function rewind()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function read($length)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getContents()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return ($key === null) ? array() : null;
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if ($this->position !== $this->size && $this->size !== null) {
+ $this->emit('error', array(new \UnderflowException('Unexpected end of response body after ' . $this->position . '/' . $this->size . ' bytes')));
+ } else {
+ $this->emit('end');
+ }
+
+ $this->close();
+ }
+}
diff --git a/vendor/clue/buzz-react/src/Message/ResponseException.php b/vendor/clue/buzz-react/src/Message/ResponseException.php
new file mode 100644
index 0000000..081103a
--- /dev/null
+++ b/vendor/clue/buzz-react/src/Message/ResponseException.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Clue\React\Buzz\Message;
+
+use RuntimeException;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * The `ResponseException` is an `Exception` sub-class that will be used to reject
+ * a request promise if the remote server returns a non-success status code
+ * (anything but 2xx or 3xx).
+ * You can control this behavior via the [`withRejectErrorResponse()` method](#withrejecterrorresponse).
+ *
+ * The `getCode(): int` method can be used to
+ * return the HTTP response status code.
+ */
+class ResponseException extends RuntimeException
+{
+ private $response;
+
+ public function __construct(ResponseInterface $response, $message = null, $code = null, $previous = null)
+ {
+ if ($message === null) {
+ $message = 'HTTP status code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ')';
+ }
+ if ($code === null) {
+ $code = $response->getStatusCode();
+ }
+ parent::__construct($message, $code, $previous);
+
+ $this->response = $response;
+ }
+
+ /**
+ * Access its underlying [`ResponseInterface`](#responseinterface) object.
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/LICENSE b/vendor/clue/connection-manager-extra/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+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/clue/connection-manager-extra/composer.json b/vendor/clue/connection-manager-extra/composer.json
new file mode 100644
index 0000000..7534f80
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "clue/connection-manager-extra",
+ "description": "Extra decorators for creating async TCP/IP connections, built on top of ReactPHP's Socket component",
+ "keywords": ["Socket", "network", "connection", "timeout", "delay", "reject", "repeat", "retry", "random", "acl", "firewall", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-connection-manager-extra",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "ConnectionManager\\Extra\\": "src" }
+ },
+ "autoload-dev": {
+ "psr-4": { "ConnectionManager\\Tests\\Extra\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/socket": "^1.0 || ^0.8 || ^0.7",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/promise-timer": "^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8"
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php
new file mode 100644
index 0000000..b5112c6
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+
+class ConnectionManagerDelay implements ConnectorInterface
+{
+ private $connectionManager;
+ private $delay;
+ private $loop;
+
+ public function __construct(ConnectorInterface $connectionManager, $delay, LoopInterface $loop)
+ {
+ $this->connectionManager = $connectionManager;
+ $this->delay = $delay;
+ $this->loop = $loop;
+ }
+
+ public function connect($uri)
+ {
+ $connectionManager = $this->connectionManager;
+
+ return Timer\resolve($this->delay, $this->loop)->then(function () use ($connectionManager, $uri) {
+ return $connectionManager->connect($uri);
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php
new file mode 100644
index 0000000..1222c83
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use Exception;
+
+// a simple connection manager that rejects every single connection attempt
+class ConnectionManagerReject implements ConnectorInterface
+{
+ private $reason = 'Connection rejected';
+
+ /**
+ * @param null|string|callable $reason
+ */
+ public function __construct($reason = null)
+ {
+ if ($reason !== null) {
+ $this->reason = $reason;
+ }
+ }
+
+ public function connect($uri)
+ {
+ $reason = $this->reason;
+ if (!is_string($reason)) {
+ try {
+ $reason = $reason($uri);
+ } catch (\Exception $e) {
+ $reason = $e;
+ }
+ }
+
+ if (!$reason instanceof \Exception) {
+ $reason = new Exception($reason);
+ }
+
+ return Promise\reject($reason);
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php
new file mode 100644
index 0000000..10f3f5a
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use InvalidArgumentException;
+use Exception;
+use React\Promise\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerRepeat implements ConnectorInterface
+{
+ protected $connectionManager;
+ protected $maximumTries;
+
+ public function __construct(ConnectorInterface $connectionManager, $maximumTries)
+ {
+ if ($maximumTries < 1) {
+ throw new InvalidArgumentException('Maximum number of tries must be >= 1');
+ }
+ $this->connectionManager = $connectionManager;
+ $this->maximumTries = $maximumTries;
+ }
+
+ public function connect($uri)
+ {
+ $tries = $this->maximumTries;
+ $connector = $this->connectionManager;
+
+ return new Promise(function ($resolve, $reject) use ($uri, &$pending, &$tries, $connector) {
+ $try = function ($error = null) use (&$try, &$pending, &$tries, $uri, $connector, $resolve, $reject) {
+ if ($tries > 0) {
+ --$tries;
+ $pending = $connector->connect($uri);
+ $pending->then($resolve, $try);
+ } else {
+ $reject(new Exception('Connection still fails even after retrying', 0, $error));
+ }
+ };
+
+ $try();
+ }, function ($_, $reject) use (&$pending, &$tries) {
+ // stop retrying, reject results and cancel pending attempt
+ $tries = 0;
+ $reject(new \RuntimeException('Cancelled'));
+
+ if ($pending instanceof CancellablePromiseInterface) {
+ $pending->cancel();
+ }
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php
new file mode 100644
index 0000000..d133225
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+
+// connection manager decorator which simplifies exchanging the actual connection manager during runtime
+class ConnectionManagerSwappable implements ConnectorInterface
+{
+ protected $connectionManager;
+
+ public function __construct(ConnectorInterface $connectionManager)
+ {
+ $this->connectionManager = $connectionManager;
+ }
+
+ public function connect($uri)
+ {
+ return $this->connectionManager->connect($uri);
+ }
+
+ public function setConnectionManager(ConnectorInterface $connectionManager)
+ {
+ $this->connectionManager = $connectionManager;
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php
new file mode 100644
index 0000000..5ec0872
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+
+class ConnectionManagerTimeout implements ConnectorInterface
+{
+ private $connectionManager;
+ private $timeout;
+ private $loop;
+
+ public function __construct(ConnectorInterface $connectionManager, $timeout, LoopInterface $loop)
+ {
+ $this->connectionManager = $connectionManager;
+ $this->timeout = $timeout;
+ $this->loop = $loop;
+ }
+
+ public function connect($uri)
+ {
+ $promise = $this->connectionManager->connect($uri);
+
+ return Timer\timeout($promise, $this->timeout, $this->loop)->then(null, function ($e) use ($promise) {
+ // connection successfully established but timeout already expired => close successful connection
+ $promise->then(function ($connection) {
+ $connection->end();
+ });
+
+ throw $e;
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php
new file mode 100644
index 0000000..c1eb9cf
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use ConnectionManager\Extra\Multiple\ConnectionManagerConsecutive;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerConcurrent extends ConnectionManagerConsecutive
+{
+ public function connect($uri)
+ {
+ $all = array();
+ foreach ($this->managers as $connector) {
+ /* @var $connection Connector */
+ $all []= $connector->connect($uri);
+ }
+ return Promise\any($all)->then(function ($conn) use ($all) {
+ // a connection attempt succeeded
+ // => cancel all pending connection attempts
+ foreach ($all as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+
+ // if promise resolves despite cancellation, immediately close stream
+ $promise->then(function ($stream) use ($conn) {
+ if ($stream !== $conn) {
+ $stream->close();
+ }
+ });
+ }
+ return $conn;
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php
new file mode 100644
index 0000000..1474b85
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use UnderflowException;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerConsecutive implements ConnectorInterface
+{
+ protected $managers;
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ */
+ public function __construct(array $managers)
+ {
+ if (!$managers) {
+ throw new \InvalidArgumentException('List of connectors must not be empty');
+ }
+ $this->managers = $managers;
+ }
+
+ public function connect($uri)
+ {
+ return $this->tryConnection($this->managers, $uri);
+ }
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ * @param string $uri
+ * @return Promise
+ * @internal
+ */
+ public function tryConnection(array $managers, $uri)
+ {
+ return new Promise\Promise(function ($resolve, $reject) use (&$managers, &$pending, $uri) {
+ $try = function () use (&$try, &$managers, $uri, $resolve, $reject, &$pending) {
+ if (!$managers) {
+ return $reject(new UnderflowException('No more managers to try to connect through'));
+ }
+
+ $manager = array_shift($managers);
+ $pending = $manager->connect($uri);
+ $pending->then($resolve, $try);
+ };
+
+ $try();
+ }, function ($_, $reject) use (&$managers, &$pending) {
+ // stop retrying, reject results and cancel pending attempt
+ $managers = array();
+ $reject(new \RuntimeException('Cancelled'));
+
+ if ($pending instanceof CancellablePromiseInterface) {
+ $pending->cancel();
+ }
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php
new file mode 100644
index 0000000..88d1fd6
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+class ConnectionManagerRandom extends ConnectionManagerConsecutive
+{
+ public function connect($uri)
+ {
+ $managers = $this->managers;
+ shuffle($managers);
+
+ return $this->tryConnection($managers, $uri);
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php
new file mode 100644
index 0000000..859ea90
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use UnderflowException;
+use InvalidArgumentException;
+
+class ConnectionManagerSelective implements ConnectorInterface
+{
+ private $managers;
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ */
+ public function __construct(array $managers)
+ {
+ foreach ($managers as $filter => $manager) {
+ $host = $filter;
+ $portMin = 0;
+ $portMax = 65535;
+
+ // search colon (either single one OR preceded by "]" due to IPv6)
+ $colon = strrpos($host, ':');
+ if ($colon !== false && (strpos($host, ':') === $colon || substr($host, $colon - 1, 1) === ']' )) {
+ if (!isset($host[$colon + 1])) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no port after colon');
+ }
+
+ $minus = strpos($host, '-', $colon);
+ if ($minus === false) {
+ $portMin = $portMax = (int)substr($host, $colon + 1);
+
+ if (substr($host, $colon + 1) !== (string)$portMin) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no valid port after colon');
+ }
+ } else {
+ $portMin = (int)substr($host, $colon + 1, ($minus - $colon));
+ $portMax = (int)substr($host, $minus + 1);
+
+ if (substr($host, $colon + 1) !== ($portMin . '-' . $portMax)) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no valid port range after colon');
+ }
+
+ if ($portMin > $portMax) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has port range mixed up');
+ }
+ }
+ $host = substr($host, 0, $colon);
+ }
+
+ if ($host === '') {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has an empty host');
+ }
+
+ if (!$manager instanceof ConnectorInterface) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" is not a valid connector');
+ }
+ }
+
+ $this->managers = $managers;
+ }
+
+ public function connect($uri)
+ {
+ $parts = parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri);
+ if (!isset($parts) || !isset($parts['scheme'], $parts['host'], $parts['port'])) {
+ return Promise\reject(new InvalidArgumentException('Invalid URI'));
+ }
+
+ $connector = $this->getConnectorForTarget(
+ trim($parts['host'], '[]'),
+ $parts['port']
+ );
+
+ if ($connector === null) {
+ return Promise\reject(new UnderflowException('No connector for given target found'));
+ }
+
+ return $connector->connect($uri);
+ }
+
+ private function getConnectorForTarget($targetHost, $targetPort)
+ {
+ foreach ($this->managers as $host => $connector) {
+ $portMin = 0;
+ $portMax = 65535;
+
+ // search colon (either single one OR preceded by "]" due to IPv6)
+ $colon = strrpos($host, ':');
+ if ($colon !== false && (strpos($host, ':') === $colon || substr($host, $colon - 1, 1) === ']' )) {
+ $minus = strpos($host, '-', $colon);
+ if ($minus === false) {
+ $portMin = $portMax = (int)substr($host, $colon + 1);
+ } else {
+ $portMin = (int)substr($host, $colon + 1, ($minus - $colon));
+ $portMax = (int)substr($host, $minus + 1);
+ }
+ $host = trim(substr($host, 0, $colon), '[]');
+ }
+
+ if ($targetPort >= $portMin && $targetPort <= $portMax && fnmatch($host, $targetHost)) {
+ return $connector;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/clue/http-proxy-react/LICENSE b/vendor/clue/http-proxy-react/LICENSE
new file mode 100644
index 0000000..7baae8e
--- /dev/null
+++ b/vendor/clue/http-proxy-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Christian Lück
+
+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/clue/http-proxy-react/composer.json b/vendor/clue/http-proxy-react/composer.json
new file mode 100644
index 0000000..9840cf0
--- /dev/null
+++ b/vendor/clue/http-proxy-react/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "clue/http-proxy-react",
+ "description": "Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP",
+ "keywords": ["HTTP", "CONNECT", "proxy", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-http-proxy",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "react/promise": " ^2.1 || ^1.2.1",
+ "react/socket": "^1.9",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\HttpProxy\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\HttpProxy\\": "tests/" }
+ }
+}
diff --git a/vendor/clue/http-proxy-react/src/ProxyConnector.php b/vendor/clue/http-proxy-react/src/ProxyConnector.php
new file mode 100644
index 0000000..0bca17e
--- /dev/null
+++ b/vendor/clue/http-proxy-react/src/ProxyConnector.php
@@ -0,0 +1,274 @@
+<?php
+
+namespace Clue\React\HttpProxy;
+
+use Exception;
+use InvalidArgumentException;
+use RuntimeException;
+use RingCentral\Psr7;
+use React\Promise;
+use React\Promise\Deferred;
+use React\Socket\ConnectionInterface;
+use React\Socket\Connector;
+use React\Socket\ConnectorInterface;
+use React\Socket\FixedUriConnector;
+use React\Socket\UnixConnector;
+
+/**
+ * A simple Connector that uses an HTTP CONNECT proxy to create plain TCP/IP connections to any destination
+ *
+ * [you] -> [proxy] -> [destination]
+ *
+ * This is most frequently used to issue HTTPS requests to your destination.
+ * However, this is actually performed on a higher protocol layer and this
+ * connector is actually inherently a general-purpose plain TCP/IP connector.
+ *
+ * Note that HTTP CONNECT proxies often restrict which ports one may connect to.
+ * Many (public) proxy servers do in fact limit this to HTTPS (443) only.
+ *
+ * If you want to establish a TLS connection (such as HTTPS) between you and
+ * your destination, you may want to wrap this connector in a SecureConnector
+ * instance.
+ *
+ * Note that communication between the client and the proxy is usually via an
+ * unencrypted, plain TCP/IP HTTP connection. Note that this is the most common
+ * setup, because you can still establish a TLS connection between you and the
+ * destination host as above.
+ *
+ * If you want to connect to a (rather rare) HTTPS proxy, you may want use its
+ * HTTPS port (443) and use a SecureConnector instance to create a secure
+ * connection to the proxy.
+ *
+ * @link https://tools.ietf.org/html/rfc7231#section-4.3.6
+ */
+class ProxyConnector implements ConnectorInterface
+{
+ private $connector;
+ private $proxyUri;
+ private $headers = '';
+
+ /**
+ * Instantiate a new ProxyConnector which uses the given $proxyUrl
+ *
+ * @param string $proxyUrl The proxy URL may or may not contain a scheme and
+ * port definition. The default port will be `80` for HTTP (or `443` for
+ * HTTPS), but many common HTTP proxy servers use custom ports.
+ * @param ?ConnectorInterface $connector (Optional) Connector to use.
+ * @param array $httpHeaders Custom HTTP headers to be sent to the proxy.
+ * @throws InvalidArgumentException if the proxy URL is invalid
+ */
+ public function __construct($proxyUrl, ConnectorInterface $connector = null, array $httpHeaders = array())
+ {
+ // support `http+unix://` scheme for Unix domain socket (UDS) paths
+ if (preg_match('/^http\+unix:\/\/(.*?@)?(.+?)$/', $proxyUrl, $match)) {
+ // rewrite URI to parse authentication from dummy host
+ $proxyUrl = 'http://' . $match[1] . 'localhost';
+
+ // connector uses Unix transport scheme and explicit path given
+ $connector = new FixedUriConnector(
+ 'unix://' . $match[2],
+ $connector ?: new UnixConnector()
+ );
+ }
+
+ if (strpos($proxyUrl, '://') === false) {
+ $proxyUrl = 'http://' . $proxyUrl;
+ }
+
+ $parts = parse_url($proxyUrl);
+ if (!$parts || !isset($parts['scheme'], $parts['host']) || ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https')) {
+ throw new InvalidArgumentException('Invalid proxy URL "' . $proxyUrl . '"');
+ }
+
+ // apply default port and TCP/TLS transport for given scheme
+ if (!isset($parts['port'])) {
+ $parts['port'] = $parts['scheme'] === 'https' ? 443 : 80;
+ }
+ $parts['scheme'] = $parts['scheme'] === 'https' ? 'tls' : 'tcp';
+
+ $this->connector = $connector ?: new Connector();
+ $this->proxyUri = $parts['scheme'] . '://' . $parts['host'] . ':' . $parts['port'];
+
+ // prepare Proxy-Authorization header if URI contains username/password
+ if (isset($parts['user']) || isset($parts['pass'])) {
+ $this->headers = 'Proxy-Authorization: Basic ' . base64_encode(
+ rawurldecode($parts['user'] . ':' . (isset($parts['pass']) ? $parts['pass'] : ''))
+ ) . "\r\n";
+ }
+
+ // append any additional custom request headers
+ foreach ($httpHeaders as $name => $values) {
+ foreach ((array)$values as $value) {
+ $this->headers .= $name . ': ' . $value . "\r\n";
+ }
+ }
+ }
+
+ public function connect($uri)
+ {
+ if (strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ }
+
+ $parts = parse_url($uri);
+ if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
+ return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
+ }
+
+ $target = $parts['host'] . ':' . $parts['port'];
+
+ // construct URI to HTTP CONNECT proxy server to connect to
+ $proxyUri = $this->proxyUri;
+
+ // append path from URI if given
+ if (isset($parts['path'])) {
+ $proxyUri .= $parts['path'];
+ }
+
+ // parse query args
+ $args = array();
+ if (isset($parts['query'])) {
+ parse_str($parts['query'], $args);
+ }
+
+ // append hostname from URI to query string unless explicitly given
+ if (!isset($args['hostname'])) {
+ $args['hostname'] = trim($parts['host'], '[]');
+ }
+
+ // append query string
+ $proxyUri .= '?' . http_build_query($args, '', '&');
+
+ // append fragment from URI if given
+ if (isset($parts['fragment'])) {
+ $proxyUri .= '#' . $parts['fragment'];
+ }
+
+ $connecting = $this->connector->connect($proxyUri);
+
+ $deferred = new Deferred(function ($_, $reject) use ($connecting, $uri) {
+ $reject(new RuntimeException(
+ 'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
+ defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
+ ));
+
+ // either close active connection or cancel pending connection attempt
+ $connecting->then(function (ConnectionInterface $stream) {
+ $stream->close();
+ });
+ $connecting->cancel();
+ });
+
+ $headers = $this->headers;
+ $connecting->then(function (ConnectionInterface $stream) use ($target, $headers, $deferred, $uri) {
+ // keep buffering data until headers are complete
+ $buffer = '';
+ $stream->on('data', $fn = function ($chunk) use (&$buffer, $deferred, $stream, &$fn, $uri) {
+ $buffer .= $chunk;
+
+ $pos = strpos($buffer, "\r\n\r\n");
+ if ($pos !== false) {
+ // end of headers received => stop buffering
+ $stream->removeListener('data', $fn);
+ $fn = null;
+
+ // try to parse headers as response message
+ try {
+ $response = Psr7\parse_response(substr($buffer, 0, $pos));
+ } catch (Exception $e) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy returned invalid response (EBADMSG)',
+ defined('SOCKET_EBADMSG') ? SOCKET_EBADMSG: 71,
+ $e
+ ));
+ $stream->close();
+ return;
+ }
+
+ if ($response->getStatusCode() === 407) {
+ // map status code 407 (Proxy Authentication Required) to EACCES
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy denied access with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (EACCES)',
+ defined('SOCKET_EACCES') ? SOCKET_EACCES : 13
+ ));
+ $stream->close();
+ return;
+ } elseif ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
+ // map non-2xx status code to ECONNREFUSED
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy refused connection with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ ));
+ $stream->close();
+ return;
+ }
+
+ // all okay, resolve with stream instance
+ $deferred->resolve($stream);
+
+ // emit remaining incoming as data event
+ $buffer = (string)substr($buffer, $pos + 4);
+ if ($buffer !== '') {
+ $stream->emit('data', array($buffer));
+ $buffer = '';
+ }
+ return;
+ }
+
+ // stop buffering when 8 KiB have been read
+ if (isset($buffer[8192])) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy response headers exceed maximum of 8 KiB (EMSGSIZE)',
+ defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 90
+ ));
+ $stream->close();
+ }
+ });
+
+ $stream->on('error', function (Exception $e) use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy caused a stream error (EIO)',
+ defined('SOCKET_EIO') ? SOCKET_EIO : 5,
+ $e
+ ));
+ });
+
+ $stream->on('close', function () use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy was lost while waiting for response (ECONNRESET)',
+ defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104
+ ));
+ });
+
+ $stream->write("CONNECT " . $target . " HTTP/1.1\r\nHost: " . $target . "\r\n" . $headers . "\r\n");
+ }, function (Exception $e) use ($deferred, $uri) {
+ $deferred->reject($e = new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
+ $e
+ ));
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as &$one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as &$arg) {
+ if ($arg instanceof \Closure) {
+ $arg = 'Object(' . get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ });
+
+ return $deferred->promise();
+ }
+}
diff --git a/vendor/clue/mq-react/LICENSE b/vendor/clue/mq-react/LICENSE
new file mode 100644
index 0000000..984ff9d
--- /dev/null
+++ b/vendor/clue/mq-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Christian Lück
+
+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/clue/mq-react/composer.json b/vendor/clue/mq-react/composer.json
new file mode 100644
index 0000000..d6e7793
--- /dev/null
+++ b/vendor/clue/mq-react/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "clue/mq-react",
+ "description": "Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP",
+ "keywords": ["Message Queue", "Mini Queue", "job", "message", "worker", "queue", "rate limit", "throttle", "concurrency", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-mq",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\Mq\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Mq\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.2.1 || ^1.2.1"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ }
+}
diff --git a/vendor/clue/mq-react/src/Queue.php b/vendor/clue/mq-react/src/Queue.php
new file mode 100644
index 0000000..7d399ac
--- /dev/null
+++ b/vendor/clue/mq-react/src/Queue.php
@@ -0,0 +1,448 @@
+<?php
+
+namespace Clue\React\Mq;
+
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+
+/**
+ * The `Queue` is responsible for managing your operations and ensuring not too
+ * many operations are executed at once. It's a very simple and lightweight
+ * in-memory implementation of the
+ * [leaky bucket](https://en.wikipedia.org/wiki/Leaky_bucket#As_a_queue) algorithm.
+ *
+ * This means that you control how many operations can be executed concurrently.
+ * If you add a job to the queue and it still below the limit, it will be executed
+ * immediately. If you keep adding new jobs to the queue and its concurrency limit
+ * is reached, it will not start a new operation and instead queue this for future
+ * execution. Once one of the pending operations complete, it will pick the next
+ * job from the queue and execute this operation.
+ */
+class Queue implements \Countable
+{
+ private $concurrency;
+ private $limit;
+ private $handler;
+
+ private $pending = 0;
+ private $queue = array();
+
+ /**
+ * Concurrently process all given jobs through the given `$handler`.
+ *
+ * This is a convenience method which uses the `Queue` internally to
+ * schedule all jobs while limiting concurrency to ensure no more than
+ * `$concurrency` jobs ever run at once. It will return a promise which
+ * resolves with the results of all jobs on success.
+ *
+ * ```php
+ * $browser = new React\Http\Browser();
+ *
+ * $promise = Queue::all(3, $urls, function ($url) use ($browser) {
+ * return $browser->get($url);
+ * });
+ *
+ * $promise->then(function (array $responses) {
+ * echo 'All ' . count($responses) . ' successful!' . PHP_EOL;
+ * });
+ * ```
+ *
+ * If either of the jobs fail, it will reject the resulting promise and will
+ * try to cancel all outstanding jobs. Similarly, calling `cancel()` on the
+ * resulting promise will try to cancel all outstanding jobs. See
+ * [promises](#promises) and [cancellation](#cancellation) for details.
+ *
+ * The `$concurrency` parameter sets a new soft limit for the maximum number
+ * of jobs to handle concurrently. Finding a good concurrency limit depends
+ * on your particular use case. It's common to limit concurrency to a rather
+ * small value, as doing more than a dozen of things at once may easily
+ * overwhelm the receiving side. Using a `1` value will ensure that all jobs
+ * are processed one after another, effectively creating a "waterfall" of
+ * jobs. Using a value less than 1 will reject with an
+ * `InvalidArgumentException` without processing any jobs.
+ *
+ * ```php
+ * // handle up to 10 jobs concurrently
+ * $promise = Queue::all(10, $jobs, $handler);
+ * ```
+ *
+ * ```php
+ * // handle each job after another without concurrency (waterfall)
+ * $promise = Queue::all(1, $jobs, $handler);
+ * ```
+ *
+ * The `$jobs` parameter must be an array with all jobs to process. Each
+ * value in this array will be passed to the `$handler` to start one job.
+ * The array keys will be preserved in the resulting array, while the array
+ * values will be replaced with the job results as returned by the
+ * `$handler`. If this array is empty, this method will resolve with an
+ * empty array without processing any jobs.
+ *
+ * The `$handler` parameter must be a valid callable that accepts your job
+ * parameters, invokes the appropriate operation and returns a Promise as a
+ * placeholder for its future result. If the given argument is not a valid
+ * callable, this method will reject with an `InvalidArgumentException`
+ * without processing any jobs.
+ *
+ * ```php
+ * // using a Closure as handler is usually recommended
+ * $promise = Queue::all(10, $jobs, function ($url) use ($browser) {
+ * return $browser->get($url);
+ * });
+ * ```
+ *
+ * ```php
+ * // accepts any callable, so PHP's array notation is also supported
+ * $promise = Queue::all(10, $jobs, array($browser, 'get'));
+ * ```
+ *
+ * > Keep in mind that returning an array of response messages means that
+ * the whole response body has to be kept in memory.
+ *
+ * @param int $concurrency concurrency soft limit
+ * @param array $jobs
+ * @param callable $handler
+ * @return PromiseInterface Returns a Promise<mixed[]> which resolves with an array of all resolution values
+ * or rejects when any of the operations reject.
+ */
+ public static function all($concurrency, array $jobs, $handler)
+ {
+ try {
+ // limit number of concurrent operations
+ $q = new self($concurrency, null, $handler);
+ } catch (\InvalidArgumentException $e) {
+ // reject if $concurrency or $handler is invalid
+ return Promise\reject($e);
+ }
+
+ // try invoking all operations and automatically queue excessive ones
+ $promises = array_map($q, $jobs);
+
+ return new Promise\Promise(function ($resolve, $reject) use ($promises) {
+ Promise\all($promises)->then($resolve, function ($e) use ($promises, $reject) {
+ // cancel all pending promises if a single promise fails
+ foreach (array_reverse($promises) as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+ }
+
+ // reject with original rejection message
+ $reject($e);
+ });
+ }, function () use ($promises) {
+ // cancel all pending promises on cancellation
+ foreach (array_reverse($promises) as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+ }
+ });
+ }
+
+ /**
+ * Concurrently process the given jobs through the given `$handler` and
+ * resolve with first resolution value.
+ *
+ * This is a convenience method which uses the `Queue` internally to
+ * schedule all jobs while limiting concurrency to ensure no more than
+ * `$concurrency` jobs ever run at once. It will return a promise which
+ * resolves with the result of the first job on success and will then try
+ * to `cancel()` all outstanding jobs.
+ *
+ * ```php
+ * $browser = new React\Http\Browser();
+ *
+ * $promise = Queue::any(3, $urls, function ($url) use ($browser) {
+ * return $browser->get($url);
+ * });
+ *
+ * $promise->then(function (ResponseInterface $response) {
+ * echo 'First response: ' . $response->getBody() . PHP_EOL;
+ * });
+ * ```
+ *
+ * If all of the jobs fail, it will reject the resulting promise. Similarly,
+ * calling `cancel()` on the resulting promise will try to cancel all
+ * outstanding jobs. See [promises](#promises) and
+ * [cancellation](#cancellation) for details.
+ *
+ * The `$concurrency` parameter sets a new soft limit for the maximum number
+ * of jobs to handle concurrently. Finding a good concurrency limit depends
+ * on your particular use case. It's common to limit concurrency to a rather
+ * small value, as doing more than a dozen of things at once may easily
+ * overwhelm the receiving side. Using a `1` value will ensure that all jobs
+ * are processed one after another, effectively creating a "waterfall" of
+ * jobs. Using a value less than 1 will reject with an
+ * `InvalidArgumentException` without processing any jobs.
+ *
+ * ```php
+ * // handle up to 10 jobs concurrently
+ * $promise = Queue::any(10, $jobs, $handler);
+ * ```
+ *
+ * ```php
+ * // handle each job after another without concurrency (waterfall)
+ * $promise = Queue::any(1, $jobs, $handler);
+ * ```
+ *
+ * The `$jobs` parameter must be an array with all jobs to process. Each
+ * value in this array will be passed to the `$handler` to start one job.
+ * The array keys have no effect, the promise will simply resolve with the
+ * job results of the first successful job as returned by the `$handler`.
+ * If this array is empty, this method will reject without processing any
+ * jobs.
+ *
+ * The `$handler` parameter must be a valid callable that accepts your job
+ * parameters, invokes the appropriate operation and returns a Promise as a
+ * placeholder for its future result. If the given argument is not a valid
+ * callable, this method will reject with an `InvalidArgumentExceptionn`
+ * without processing any jobs.
+ *
+ * ```php
+ * // using a Closure as handler is usually recommended
+ * $promise = Queue::any(10, $jobs, function ($url) use ($browser) {
+ * return $browser->get($url);
+ * });
+ * ```
+ *
+ * ```php
+ * // accepts any callable, so PHP's array notation is also supported
+ * $promise = Queue::any(10, $jobs, array($browser, 'get'));
+ * ```
+ *
+ * @param int $concurrency concurrency soft limit
+ * @param array $jobs
+ * @param callable $handler
+ * @return PromiseInterface Returns a Promise<mixed> which resolves with a single resolution value
+ * or rejects when all of the operations reject.
+ */
+ public static function any($concurrency, array $jobs, $handler)
+ {
+ // explicitly reject with empty jobs (https://github.com/reactphp/promise/pull/34)
+ if (!$jobs) {
+ return Promise\reject(new \UnderflowException('No jobs given'));
+ }
+
+ try {
+ // limit number of concurrent operations
+ $q = new self($concurrency, null, $handler);
+ } catch (\InvalidArgumentException $e) {
+ // reject if $concurrency or $handler is invalid
+ return Promise\reject($e);
+ }
+
+ // try invoking all operations and automatically queue excessive ones
+ $promises = array_map($q, $jobs);
+
+ return new Promise\Promise(function ($resolve, $reject) use ($promises) {
+ Promise\any($promises)->then(function ($result) use ($promises, $resolve) {
+ // cancel all pending promises if a single result is ready
+ foreach (array_reverse($promises) as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+ }
+
+ // resolve with original resolution value
+ $resolve($result);
+ }, $reject);
+ }, function () use ($promises) {
+ // cancel all pending promises on cancellation
+ foreach (array_reverse($promises) as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+ }
+ });
+ }
+
+ /**
+ * Instantiates a new queue object.
+ *
+ * You can create any number of queues, for example when you want to apply
+ * different limits to different kind of operations.
+ *
+ * The `$concurrency` parameter sets a new soft limit for the maximum number
+ * of jobs to handle concurrently. Finding a good concurrency limit depends
+ * on your particular use case. It's common to limit concurrency to a rather
+ * small value, as doing more than a dozen of things at once may easily
+ * overwhelm the receiving side.
+ *
+ * The `$limit` parameter sets a new hard limit on how many jobs may be
+ * outstanding (kept in memory) at once. Depending on your particular use
+ * case, it's usually safe to keep a few hundreds or thousands of jobs in
+ * memory. If you do not want to apply an upper limit, you can pass a `null`
+ * value which is semantically more meaningful than passing a big number.
+ *
+ * ```php
+ * // handle up to 10 jobs concurrently, but keep no more than 1000 in memory
+ * $q = new Queue(10, 1000, $handler);
+ * ```
+ *
+ * ```php
+ * // handle up to 10 jobs concurrently, do not limit queue size
+ * $q = new Queue(10, null, $handler);
+ * ```
+ *
+ * ```php
+ * // handle up to 10 jobs concurrently, reject all further jobs
+ * $q = new Queue(10, 10, $handler);
+ * ```
+ *
+ * The `$handler` parameter must be a valid callable that accepts your job
+ * parameters, invokes the appropriate operation and returns a Promise as a
+ * placeholder for its future result.
+ *
+ * ```php
+ * // using a Closure as handler is usually recommended
+ * $q = new Queue(10, null, function ($url) use ($browser) {
+ * return $browser->get($url);
+ * });
+ * ```
+ *
+ * ```php
+ * // PHP's array callable as handler is also supported
+ * $q = new Queue(10, null, array($browser, 'get'));
+ * ```
+ *
+ * @param int $concurrency concurrency soft limit
+ * @param int|null $limit queue hard limit or NULL=unlimited
+ * @param callable $handler
+ * @throws \InvalidArgumentException
+ */
+ public function __construct($concurrency, $limit, $handler)
+ {
+ if ($concurrency < 1 || ($limit !== null && ($limit < 1 || $concurrency > $limit))) {
+ throw new \InvalidArgumentException('Invalid limit given');
+ }
+ if (!is_callable($handler)) {
+ throw new \InvalidArgumentException('Invalid handler given');
+ }
+
+ $this->concurrency = $concurrency;
+ $this->limit = $limit;
+ $this->handler = $handler;
+ }
+
+ /**
+ * The Queue instance is invokable, so that invoking `$q(...$args)` will
+ * actually be forwarded as `$handler(...$args)` as given in the
+ * `$handler` argument when concurrency is still below limits.
+ *
+ * Each operation may take some time to complete, but due to its async nature you
+ * can actually start any number of (queued) operations. Once the concurrency limit
+ * is reached, this invocation will simply be queued and this will return a pending
+ * promise which will start the actual operation once another operation is
+ * completed. This means that this is handled entirely transparently and you do not
+ * need to worry about this concurrency limit yourself.
+ *
+ * @return \React\Promise\PromiseInterface
+ */
+ public function __invoke()
+ {
+ // happy path: simply invoke handler if we're below concurrency limit
+ if ($this->pending < $this->concurrency) {
+ ++$this->pending;
+
+ // invoke handler and await its resolution before invoking next queued job
+ return $this->await(
+ call_user_func_array($this->handler, func_get_args())
+ );
+ }
+
+ // we're currently above concurrency limit, make sure we do not exceed maximum queue limit
+ if ($this->limit !== null && $this->count() >= $this->limit) {
+ return Promise\reject(new \OverflowException('Maximum queue limit of ' . $this->limit . ' exceeded'));
+ }
+
+ // if we reach this point, then this job will need to be queued
+ // get next queue position
+ $queue =& $this->queue;
+ $queue[] = null;
+ end($queue);
+ $id = key($queue);
+
+ $deferred = new Deferred(function ($_, $reject) use (&$queue, $id, &$deferred) {
+ // forward cancellation to pending operation if it is currently executing
+ if (isset($deferred->pending) && $deferred->pending instanceof CancellablePromiseInterface) {
+ $deferred->pending->cancel();
+ }
+ unset($deferred->pending);
+
+ if (isset($deferred->args)) {
+ // queued promise cancelled before its handler is invoked
+ // remove from queue and reject explicitly
+ unset($queue[$id], $deferred->args);
+ $reject(new \RuntimeException('Cancelled queued job before processing started'));
+ }
+ });
+
+ // queue job to process if number of pending jobs is below concurrency limit again
+ $deferred->args = func_get_args();
+ $queue[$id] = $deferred;
+
+ return $deferred->promise();
+ }
+
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return $this->pending + count($this->queue);
+ }
+
+ /**
+ * @internal
+ */
+ public function await(PromiseInterface $promise)
+ {
+ $that = $this;
+
+ return $promise->then(function ($result) use ($that) {
+ $that->processQueue();
+
+ return $result;
+ }, function ($error) use ($that) {
+ $that->processQueue();
+
+ return Promise\reject($error);
+ });
+ }
+
+ /**
+ * @internal
+ */
+ public function processQueue()
+ {
+ // skip if we're still above concurrency limit or there's no queued job waiting
+ if (--$this->pending >= $this->concurrency || !$this->queue) {
+ return;
+ }
+
+ /* @var $deferred Deferred */
+ $deferred = reset($this->queue);
+ unset($this->queue[key($this->queue)]);
+
+ // once number of pending jobs is below concurrency limit again:
+ // await this situation, invoke handler and await its resolution before invoking next queued job
+ ++$this->pending;
+
+ $promise = call_user_func_array($this->handler, $deferred->args);
+ $deferred->pending = $promise;
+ unset($deferred->args);
+
+ // invoke handler and await its resolution before invoking next queued job
+ $this->await($promise)->then(
+ function ($result) use ($deferred) {
+ unset($deferred->pending);
+ $deferred->resolve($result);
+ },
+ function ($e) use ($deferred) {
+ unset($deferred->pending);
+ $deferred->reject($e);
+ }
+ );
+ }
+}
diff --git a/vendor/clue/redis-protocol/composer.json b/vendor/clue/redis-protocol/composer.json
new file mode 100644
index 0000000..d99e2ee
--- /dev/null
+++ b/vendor/clue/redis-protocol/composer.json
@@ -0,0 +1,19 @@
+{
+ "name": "clue/redis-protocol",
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "keywords": ["streaming", "redis", "protocol", "parser", "serializer"],
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "require": {
+ "php": ">=5.3"
+ },
+ "autoload": {
+ "psr-0": { "Clue\\Redis\\Protocol": "src" }
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
new file mode 100644
index 0000000..3997f04
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Clue\Redis\Protocol;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Parser\ResponseParser;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Clue\Redis\Protocol\Serializer\RecursiveSerializer;
+use Clue\Redis\Protocol\Parser\RequestParser;
+
+/**
+ * Provides factory methods used to instantiate the best available protocol implementation
+ */
+class Factory
+{
+ /**
+ * instantiate the best available protocol response parser implementation
+ *
+ * This is the parser every redis client implementation should use in order
+ * to parse incoming response messages from a redis server.
+ *
+ * @return ParserInterface
+ */
+ public function createResponseParser()
+ {
+ return new ResponseParser();
+ }
+
+ /**
+ * instantiate the best available protocol request parser implementation
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests.
+ *
+ * @return ParserInterface
+ */
+ public function createRequestParser()
+ {
+ return new RequestParser();
+ }
+
+ /**
+ * instantiate the best available protocol serializer implementation
+ *
+ * @return SerializerInterface
+ */
+ public function createSerializer()
+ {
+ return new RecursiveSerializer();
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
new file mode 100644
index 0000000..e069fda
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class BulkReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create bulk reply (string reply)
+ *
+ * @param string|null $data
+ */
+ public function __construct($value)
+ {
+ if ($value !== null) {
+ $value = (string)$value;
+ }
+ $this->value = $value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getBulkMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
new file mode 100644
index 0000000..556e93b
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Exception;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class ErrorReply extends Exception implements ModelInterface
+{
+ /**
+ * create error status reply (single line error message)
+ *
+ * @param string|ErrorReplyException $message
+ * @return string
+ */
+ public function __construct($message, $code = 0, $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
+
+ public function getValueNative()
+ {
+ return $this->getMessage();
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getErrorMessage($this->getMessage());
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
new file mode 100644
index 0000000..ba1ff05
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class IntegerReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create integer reply
+ *
+ * @param int $data
+ */
+ public function __construct($value)
+ {
+ $this->value = (int)$value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getIntegerMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
new file mode 100644
index 0000000..b97939e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+interface ModelInterface
+{
+ /**
+ * Returns value of this model as a native representation for PHP
+ *
+ * @return mixed
+ */
+ public function getValueNative();
+
+ /**
+ * Returns the serialized representation of this protocol message
+ *
+ * @param SerializerInterface $serializer;
+ * @return string
+ */
+ public function getMessageSerialized(SerializerInterface $serializer);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
new file mode 100644
index 0000000..7198dc6
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use InvalidArgumentException;
+use UnexpectedValueException;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class MultiBulkReply implements ModelInterface
+{
+ /**
+ * @var array|null
+ */
+ private $data;
+
+ /**
+ * create multi bulk reply (an array of other replies, usually bulk replies)
+ *
+ * @param array|null $data
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $data = null)
+ {
+ $this->data = $data;
+ }
+
+ public function getValueNative()
+ {
+ if ($this->data === null) {
+ return null;
+ }
+
+ $ret = array();
+ foreach ($this->data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret []= $one->getValueNative();
+ } else {
+ $ret []= $one;
+ }
+ }
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getMultiBulkMessage($this->data);
+ }
+
+ /**
+ * Checks whether this model represents a valid unified request protocol message
+ *
+ * The new unified protocol was introduced in Redis 1.2, but it became the
+ * standard way for talking with the Redis server in Redis 2.0. The unified
+ * request protocol is what Redis already uses in replies in order to send
+ * list of items to clients, and is called a Multi Bulk Reply.
+ *
+ * @return boolean
+ * @link http://redis.io/topics/protocol
+ */
+ public function isRequest()
+ {
+ if (!$this->data) {
+ return false;
+ }
+
+ foreach ($this->data as $one) {
+ if (!($one instanceof BulkReply) && !is_string($one)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function getRequestModel()
+ {
+ if (!$this->data) {
+ throw new UnexpectedValueException('Null-multi-bulk message can not be represented as a request, must contain string/bulk values');
+ }
+
+ $command = null;
+ $args = array();
+
+ foreach ($this->data as $one) {
+ if ($one instanceof BulkReply) {
+ $one = $one->getValueNative();
+ } elseif (!is_string($one)) {
+ throw new UnexpectedValueException('Message can not be represented as a request, must only contain string/bulk values');
+ }
+
+ if ($command === null) {
+ $command = $one;
+ } else {
+ $args []= $one;
+ }
+ }
+
+ return new Request($command, $args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
new file mode 100644
index 0000000..f5881e9
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class Request implements ModelInterface
+{
+ private $command;
+ private $args;
+
+ public function __construct($command, array $args = array())
+ {
+ $this->command = $command;
+ $this->args = $args;
+ }
+
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ public function getArgs()
+ {
+ return $this->args;
+ }
+
+ public function getReplyModel()
+ {
+ $models = array(new BulkReply($this->command));
+ foreach ($this->args as $arg) {
+ $models []= new BulkReply($arg);
+ }
+
+ return new MultiBulkReply($models);
+ }
+
+ public function getValueNative()
+ {
+ $ret = $this->args;
+ array_unshift($ret, $this->command);
+
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getRequestMessage($this->command, $this->args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
new file mode 100644
index 0000000..4ea2fcd
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class StatusReply implements ModelInterface
+{
+ private $message;
+
+ /**
+ * create status reply (single line message)
+ *
+ * @param string|Status $message
+ * @return string
+ */
+ public function __construct($message)
+ {
+ $this->message = $message;
+ }
+
+ public function getValueNative()
+ {
+ return $this->message;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getStatusMessage($this->message);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
new file mode 100644
index 0000000..c1e3001
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnderflowException;
+
+class MessageBuffer implements ParserInterface
+{
+ private $parser;
+ private $incomingQueue = array();
+
+ public function __construct(ParserInterface $parser)
+ {
+ $this->parser = $parser;
+ }
+
+ public function popIncomingModel()
+ {
+ if (!$this->incomingQueue) {
+ throw new UnderflowException('Incoming message queue is empty');
+ }
+ return array_shift($this->incomingQueue);
+ }
+
+ public function hasIncomingModel()
+ {
+ return ($this->incomingQueue) ? true : false;
+ }
+
+ public function pushIncoming($data)
+ {
+ $ret = $this->parser->pushIncoming($data);
+
+ foreach ($ret as $one) {
+ $this->incomingQueue []= $one;
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
new file mode 100644
index 0000000..e57c5bc
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnexpectedValueException;
+
+class ParserException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
new file mode 100644
index 0000000..a322719
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+interface ParserInterface
+{
+ /**
+ * push a chunk of the redis protocol message into the buffer and parse
+ *
+ * You can push any number of bytes of a redis protocol message into the
+ * parser and it will try to parse messages from its data stream. So you can
+ * pass data directly from your socket stream and the parser will return the
+ * right amount of message model objects for you.
+ *
+ * If you pass an incomplete message, expect it to return an empty array. If
+ * your incomplete message is split to across multiple chunks, the parsed
+ * message model will be returned once the parser has sufficient data.
+ *
+ * @param string $dataChunk
+ * @return ModelInterface[] 0+ message models
+ * @throws ParserException if the message can not be parsed
+ * @see self::popIncomingModel()
+ */
+ public function pushIncoming($dataChunk);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
new file mode 100644
index 0000000..a47d137
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserException;
+use Clue\Redis\Protocol\Model\Request;
+
+class RequestParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ $parsed = array();
+
+ do {
+ $saved = $this->incomingOffset;
+ $message = $this->readRequest();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = $saved;
+ break;
+ }
+
+ if ($message !== false) {
+ $parsed []= $message;
+ }
+ } while($this->incomingBuffer !== '');
+
+ if ($this->incomingOffset !== 0) {
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * try to parse request from incoming buffer
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return Request|null
+ */
+ private function readRequest()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line starts with a multi-bulk header "*"
+ if (isset($this->incomingBuffer[$this->incomingOffset]) && $this->incomingBuffer[$this->incomingOffset] === '*') {
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $count = (int)$line;
+
+ if ($count <= 0) {
+ return false;
+ }
+ $command = null;
+ $args = array();
+ for ($i = 0; $i < $count; ++$i) {
+ $sub = $this->readBulk();
+ if ($sub === null) {
+ return null;
+ }
+ if ($command === null) {
+ $command = $sub;
+ } else {
+ $args []= $sub;
+ }
+ }
+ return new Request($command, $args);
+ }
+
+ // parse an old inline request instead
+ $line = substr($this->incomingBuffer, $this->incomingOffset, $crlf - $this->incomingOffset);
+ $this->incomingOffset = $crlf + 2;
+
+ $args = preg_split('/ +/', trim($line, ' '));
+ $command = array_shift($args);
+
+ if ($command === '') {
+ return false;
+ }
+
+ return new Request($command, $args);
+ }
+
+ private function readBulk()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line has to start with a bulk header "$"
+ if (!isset($this->incomingBuffer[$this->incomingOffset]) || $this->incomingBuffer[$this->incomingOffset] !== '$') {
+ throw new ParserException('ERR Protocol error: expected \'$\', got \'' . substr($this->incomingBuffer, $this->incomingOffset, 1) . '\'');
+ }
+
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $size = (int)$line;
+
+ if ($size < 0) {
+ throw new ParserException('ERR Protocol error: invalid bulk length');
+ }
+
+ if (!isset($this->incomingBuffer[$this->incomingOffset + $size + 1])) {
+ // check enough bytes + crlf are buffered
+ return null;
+ }
+
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $size);
+ $this->incomingOffset += $size + 2;
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
new file mode 100644
index 0000000..19ac90c
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\StatusReply;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+/**
+ * Simple recursive redis wire protocol parser
+ *
+ * Heavily influenced by blocking parser implementation from jpd/redisent.
+ *
+ * @link https://github.com/jdp/redisent
+ * @link http://redis.io/topics/protocol
+ */
+class ResponseParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ return $this->tryParsingIncomingMessages();
+ }
+
+ private function tryParsingIncomingMessages()
+ {
+ $messages = array();
+
+ do {
+ $message = $this->readResponse();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = 0;
+ break;
+ }
+
+ $messages []= $message;
+
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ } while($this->incomingBuffer !== '');
+
+ return $messages;
+ }
+
+ private function readLine()
+ {
+ $pos = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+
+ if ($pos === false) {
+ return null;
+ }
+
+ $ret = (string)substr($this->incomingBuffer, $this->incomingOffset, $pos - $this->incomingOffset);
+ $this->incomingOffset = $pos + 2;
+
+ return $ret;
+ }
+
+ private function readLength($len)
+ {
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $len);
+ if (strlen($ret) !== $len) {
+ return null;
+ }
+
+ $this->incomingOffset += $len;
+
+ return $ret;
+ }
+
+ /**
+ * try to parse response from incoming buffer
+ *
+ * ripped from jdp/redisent, with some minor modifications to read from
+ * the incoming buffer instead of issuing a blocking fread on a stream
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return ModelInterface|null
+ * @link https://github.com/jdp/redisent
+ */
+ private function readResponse()
+ {
+ /* Parse the response based on the reply identifier */
+ $reply = $this->readLine();
+ if ($reply === null) {
+ return null;
+ }
+ switch (substr($reply, 0, 1)) {
+ /* Error reply */
+ case '-':
+ $response = new ErrorReply(substr($reply, 1));
+ break;
+ /* Inline reply */
+ case '+':
+ $response = new StatusReply(substr($reply, 1));
+ break;
+ /* Bulk reply */
+ case '$':
+ $size = (int)substr($reply, 1);
+ if ($size === -1) {
+ return new BulkReply(null);
+ }
+ $data = $this->readLength($size);
+ if ($data === null) {
+ return null;
+ }
+ if ($this->readLength(2) === null) { /* discard crlf */
+ return null;
+ }
+ $response = new BulkReply($data);
+ break;
+ /* Multi-bulk reply */
+ case '*':
+ $count = (int)substr($reply, 1);
+ if ($count === -1) {
+ return new MultiBulkReply(null);
+ }
+ $response = array();
+ for ($i = 0; $i < $count; $i++) {
+ $sub = $this->readResponse();
+ if ($sub === null) {
+ return null;
+ }
+ $response []= $sub;
+ }
+ $response = new MultiBulkReply($response);
+ break;
+ /* Integer reply */
+ case ':':
+ $response = new IntegerReply(substr($reply, 1));
+ break;
+ default:
+ throw new ParserException('Invalid message can not be parsed: "' . $reply . '"');
+ break;
+ }
+ /* Party on */
+ return $response;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
new file mode 100644
index 0000000..6e25125
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\StatusReply;
+use InvalidArgumentException;
+use Exception;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\Request;
+
+class RecursiveSerializer implements SerializerInterface
+{
+ const CRLF = "\r\n";
+
+ public function getRequestMessage($command, array $args = array())
+ {
+ $data = '*' . (count($args) + 1) . "\r\n$" . strlen($command) . "\r\n" . $command . "\r\n";
+ foreach ($args as $arg) {
+ $data .= '$' . strlen($arg) . "\r\n" . $arg . "\r\n";
+ }
+ return $data;
+ }
+
+ public function createRequestModel($command, array $args = array())
+ {
+ return new Request($command, $args);
+ }
+
+ public function getReplyMessage($data)
+ {
+ if (is_string($data) || $data === null) {
+ return $this->getBulkMessage($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return $this->getIntegerMessage($data);
+ } else if ($data instanceof Exception) {
+ return $this->getErrorMessage($data->getMessage());
+ } else if (is_array($data)) {
+ return $this->getMultiBulkMessage($data);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function createReplyModel($data)
+ {
+ if (is_string($data) || $data === null) {
+ return new BulkReply($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return new IntegerReply($data);
+ } else if ($data instanceof Exception) {
+ return new ErrorReply($data->getMessage());
+ } else if (is_array($data)) {
+ $models = array();
+ foreach ($data as $one) {
+ $models []= $this->createReplyModel($one);
+ }
+ return new MultiBulkReply($models);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function getBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null bulk reply */
+ return '$-1' . self::CRLF;
+ }
+ /* bulk reply */
+ return '$' . strlen($data) . self::CRLF . $data . self::CRLF;
+ }
+
+ public function getErrorMessage($data)
+ {
+ /* error status reply */
+ return '-' . $data . self::CRLF;
+ }
+
+ public function getIntegerMessage($data)
+ {
+ return ':' . (int)$data . self::CRLF;
+ }
+
+ public function getMultiBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null multi bulk reply */
+ return '*-1' . self::CRLF;
+ }
+ /* multi bulk reply */
+ $ret = '*' . count($data) . self::CRLF;
+ foreach ($data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret .= $one->getMessageSerialized($this);
+ } else {
+ $ret .= $this->getReplyMessage($one);
+ }
+ }
+ return $ret;
+ }
+
+ public function getStatusMessage($data)
+ {
+ /* status reply */
+ return '+' . $data . self::CRLF;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
new file mode 100644
index 0000000..bb7cb3e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\ErrorReplyException;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+
+interface SerializerInterface
+{
+ /**
+ * create a serialized unified request protocol message
+ *
+ * This is the *one* method most redis client libraries will likely want to
+ * use in order to send a serialized message (a request) over the* wire to
+ * your redis server instance.
+ *
+ * This method should be used in favor of constructing a request model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * @param string $command
+ * @param array $args
+ * @return string
+ * @see self::createRequestMessage()
+ */
+ public function getRequestMessage($command, array $args = array());
+
+ /**
+ * create a unified request protocol message model
+ *
+ * @param string $command
+ * @param array $args
+ * @return MultiBulkReply
+ */
+ public function createRequestModel($command, array $args = array());
+
+ /**
+ * create a serialized unified protocol reply message
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests and send resulting reply messages.
+ *
+ * This method does its best to guess to right reply type and then returns
+ * a serialized version of the message. It follows the "redis to lua
+ * conversion table" (see link) which means most basic types can be mapped
+ * as is.
+ *
+ * This method should be used in favor of constructing a reply model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * Note however, you may still want to explicitly create a nested reply
+ * model hierarchy if you need more control over the serialized message. For
+ * instance, a null value will always be returned as a Null-Bulk-Reply, so
+ * there's no way to express a Null-Multi-Bulk-Reply, unless you construct
+ * it explicitly.
+ *
+ * @param mixed $data
+ * @return string
+ * @see self::createReplyModel()
+ * @link http://redis.io/commands/eval
+ */
+ public function getReplyMessage($data);
+
+ /**
+ * create response message by determining datatype from given argument
+ *
+ * @param mixed $data
+ * @return ModelInterface
+ */
+ public function createReplyModel($data);
+
+ public function getBulkMessage($data);
+
+ public function getErrorMessage($data);
+
+ public function getIntegerMessage($data);
+
+ public function getMultiBulkMessage($data);
+
+ public function getStatusMessage($data);
+}
diff --git a/vendor/clue/redis-react/LICENSE b/vendor/clue/redis-react/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/redis-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+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/clue/redis-react/composer.json b/vendor/clue/redis-react/composer.json
new file mode 100644
index 0000000..c1752cc
--- /dev/null
+++ b/vendor/clue/redis-react/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "clue/redis-react",
+ "description": "Async Redis client implementation, built on top of ReactPHP.",
+ "keywords": ["Redis", "database", "client", "async", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-redis",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "clue/redis-protocol": "0.3.*",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.0 || ^1.1",
+ "react/promise-timer": "^1.8",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\Redis\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Redis\\": "tests/" }
+ }
+}
diff --git a/vendor/clue/redis-react/src/Client.php b/vendor/clue/redis-react/src/Client.php
new file mode 100644
index 0000000..ec54229
--- /dev/null
+++ b/vendor/clue/redis-react/src/Client.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Evenement\EventEmitterInterface;
+use React\Promise\PromiseInterface;
+
+/**
+ * Simple interface for executing redis commands
+ *
+ * @event error(Exception $error)
+ * @event close()
+ *
+ * @event message($channel, $message)
+ * @event subscribe($channel, $numberOfChannels)
+ * @event unsubscribe($channel, $numberOfChannels)
+ *
+ * @event pmessage($pattern, $channel, $message)
+ * @event psubscribe($channel, $numberOfChannels)
+ * @event punsubscribe($channel, $numberOfChannels)
+ */
+interface Client extends EventEmitterInterface
+{
+ /**
+ * Invoke the given command and return a Promise that will be fulfilled when the request has been replied to
+ *
+ * This is a magic method that will be invoked when calling any redis
+ * command on this instance.
+ *
+ * @param string $name
+ * @param string[] $args
+ * @return PromiseInterface Promise<mixed,Exception>
+ */
+ public function __call($name, $args);
+
+ /**
+ * end connection once all pending requests have been replied to
+ *
+ * @return void
+ * @uses self::close() once all replies have been received
+ * @see self::close() for closing the connection immediately
+ */
+ public function end();
+
+ /**
+ * close connection immediately
+ *
+ * This will emit the "close" event.
+ *
+ * @return void
+ * @see self::end() for closing the connection once the client is idle
+ */
+ public function close();
+}
diff --git a/vendor/clue/redis-react/src/Factory.php b/vendor/clue/redis-react/src/Factory.php
new file mode 100644
index 0000000..4e94905
--- /dev/null
+++ b/vendor/clue/redis-react/src/Factory.php
@@ -0,0 +1,191 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Clue\Redis\Protocol\Factory as ProtocolFactory;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Deferred;
+use React\Promise\Timer\TimeoutException;
+use React\Socket\ConnectionInterface;
+use React\Socket\Connector;
+use React\Socket\ConnectorInterface;
+
+class Factory
+{
+ /** @var LoopInterface */
+ private $loop;
+
+ /** @var ConnectorInterface */
+ private $connector;
+
+ /** @var ProtocolFactory */
+ private $protocol;
+
+ /**
+ * @param ?LoopInterface $loop
+ * @param ?ConnectorInterface $connector
+ * @param ?ProtocolFactory $protocol
+ */
+ public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null, ProtocolFactory $protocol = null)
+ {
+ $this->loop = $loop ?: Loop::get();
+ $this->connector = $connector ?: new Connector(array(), $this->loop);
+ $this->protocol = $protocol ?: new ProtocolFactory();
+ }
+
+ /**
+ * Create Redis client connected to address of given redis instance
+ *
+ * @param string $uri Redis server URI to connect to
+ * @return \React\Promise\PromiseInterface<Client,\Exception> Promise that will
+ * be fulfilled with `Client` on success or rejects with `\Exception` on error.
+ */
+ public function createClient($uri)
+ {
+ // support `redis+unix://` scheme for Unix domain socket (UDS) paths
+ if (preg_match('/^(redis\+unix:\/\/(?:[^:]*:[^@]*@)?)(.+?)?$/', $uri, $match)) {
+ $parts = parse_url($match[1] . 'localhost/' . $match[2]);
+ } else {
+ if (strpos($uri, '://') === false) {
+ $uri = 'redis://' . $uri;
+ }
+
+ $parts = parse_url($uri);
+ }
+
+ $uri = preg_replace(array('/(:)[^:\/]*(@)/', '/([?&]password=).*?($|&)/'), '$1***$2', $uri);
+ if ($parts === false || !isset($parts['scheme'], $parts['host']) || !in_array($parts['scheme'], array('redis', 'rediss', 'redis+unix'))) {
+ return \React\Promise\reject(new \InvalidArgumentException(
+ 'Invalid Redis URI given (EINVAL)',
+ defined('SOCKET_EINVAL') ? SOCKET_EINVAL : 22
+ ));
+ }
+
+ $args = array();
+ parse_str(isset($parts['query']) ? $parts['query'] : '', $args);
+
+ $authority = $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 6379);
+ if ($parts['scheme'] === 'rediss') {
+ $authority = 'tls://' . $authority;
+ } elseif ($parts['scheme'] === 'redis+unix') {
+ $authority = 'unix://' . substr($parts['path'], 1);
+ unset($parts['path']);
+ }
+ $connecting = $this->connector->connect($authority);
+
+ $deferred = new Deferred(function ($_, $reject) use ($connecting, $uri) {
+ // connection cancelled, start with rejecting attempt, then clean up
+ $reject(new \RuntimeException(
+ 'Connection to ' . $uri . ' cancelled (ECONNABORTED)',
+ defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
+ ));
+
+ // either close successful connection or cancel pending connection attempt
+ $connecting->then(function (ConnectionInterface $connection) {
+ $connection->close();
+ });
+ $connecting->cancel();
+ });
+
+ $protocol = $this->protocol;
+ $promise = $connecting->then(function (ConnectionInterface $stream) use ($protocol) {
+ return new StreamingClient($stream, $protocol->createResponseParser(), $protocol->createSerializer());
+ }, function (\Exception $e) use ($uri) {
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' failed: ' . $e->getMessage(),
+ $e->getCode(),
+ $e
+ );
+ });
+
+ // use `?password=secret` query or `user:secret@host` password form URL
+ $pass = isset($args['password']) ? $args['password'] : (isset($parts['pass']) ? rawurldecode($parts['pass']) : null);
+ if (isset($args['password']) || isset($parts['pass'])) {
+ $pass = isset($args['password']) ? $args['password'] : rawurldecode($parts['pass']);
+ $promise = $promise->then(function (StreamingClient $redis) use ($pass, $uri) {
+ return $redis->auth($pass)->then(
+ function () use ($redis) {
+ return $redis;
+ },
+ function (\Exception $e) use ($redis, $uri) {
+ $redis->close();
+
+ $const = '';
+ $errno = $e->getCode();
+ if ($errno === 0) {
+ $const = ' (EACCES)';
+ $errno = $e->getCode() ?: (defined('SOCKET_EACCES') ? SOCKET_EACCES : 13);
+ }
+
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' failed during AUTH command: ' . $e->getMessage() . $const,
+ $errno,
+ $e
+ );
+ }
+ );
+ });
+ }
+
+ // use `?db=1` query or `/1` path (skip first slash)
+ if (isset($args['db']) || (isset($parts['path']) && $parts['path'] !== '/')) {
+ $db = isset($args['db']) ? $args['db'] : substr($parts['path'], 1);
+ $promise = $promise->then(function (StreamingClient $redis) use ($db, $uri) {
+ return $redis->select($db)->then(
+ function () use ($redis) {
+ return $redis;
+ },
+ function (\Exception $e) use ($redis, $uri) {
+ $redis->close();
+
+ $const = '';
+ $errno = $e->getCode();
+ if ($errno === 0 && strpos($e->getMessage(), 'NOAUTH ') === 0) {
+ $const = ' (EACCES)';
+ $errno = defined('SOCKET_EACCES') ? SOCKET_EACCES : 13;
+ } elseif ($errno === 0) {
+ $const = ' (ENOENT)';
+ $errno = defined('SOCKET_ENOENT') ? SOCKET_ENOENT : 2;
+ }
+
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' failed during SELECT command: ' . $e->getMessage() . $const,
+ $errno,
+ $e
+ );
+ }
+ );
+ });
+ }
+
+ $promise->then(array($deferred, 'resolve'), array($deferred, 'reject'));
+
+ // use timeout from explicit ?timeout=x parameter or default to PHP's default_socket_timeout (60)
+ $timeout = isset($args['timeout']) ? (float) $args['timeout'] : (int) ini_get("default_socket_timeout");
+ if ($timeout < 0) {
+ return $deferred->promise();
+ }
+
+ return \React\Promise\Timer\timeout($deferred->promise(), $timeout, $this->loop)->then(null, function ($e) use ($uri) {
+ if ($e instanceof TimeoutException) {
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' timed out after ' . $e->getTimeout() . ' seconds (ETIMEDOUT)',
+ defined('SOCKET_ETIMEDOUT') ? SOCKET_ETIMEDOUT : 110
+ );
+ }
+ throw $e;
+ });
+ }
+
+ /**
+ * Create Redis client connected to address of given redis instance
+ *
+ * @param string $target
+ * @return Client
+ */
+ public function createLazyClient($target)
+ {
+ return new LazyClient($target, $this, $this->loop);
+ }
+}
diff --git a/vendor/clue/redis-react/src/LazyClient.php b/vendor/clue/redis-react/src/LazyClient.php
new file mode 100644
index 0000000..d82b257
--- /dev/null
+++ b/vendor/clue/redis-react/src/LazyClient.php
@@ -0,0 +1,219 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Evenement\EventEmitter;
+use React\Stream\Util;
+use React\EventLoop\LoopInterface;
+
+/**
+ * @internal
+ */
+class LazyClient extends EventEmitter implements Client
+{
+ private $target;
+ /** @var Factory */
+ private $factory;
+ private $closed = false;
+ private $promise;
+
+ private $loop;
+ private $idlePeriod = 60.0;
+ private $idleTimer;
+ private $pending = 0;
+
+ private $subscribed = array();
+ private $psubscribed = array();
+
+ /**
+ * @param $target
+ */
+ public function __construct($target, Factory $factory, LoopInterface $loop)
+ {
+ $args = array();
+ \parse_str((string) \parse_url($target, \PHP_URL_QUERY), $args);
+ if (isset($args['idle'])) {
+ $this->idlePeriod = (float)$args['idle'];
+ }
+
+ $this->target = $target;
+ $this->factory = $factory;
+ $this->loop = $loop;
+ }
+
+ private function client()
+ {
+ if ($this->promise !== null) {
+ return $this->promise;
+ }
+
+ $self = $this;
+ $pending =& $this->promise;
+ $idleTimer=& $this->idleTimer;
+ $subscribed =& $this->subscribed;
+ $psubscribed =& $this->psubscribed;
+ $loop = $this->loop;
+ return $pending = $this->factory->createClient($this->target)->then(function (Client $redis) use ($self, &$pending, &$idleTimer, &$subscribed, &$psubscribed, $loop) {
+ // connection completed => remember only until closed
+ $redis->on('close', function () use (&$pending, $self, &$subscribed, &$psubscribed, &$idleTimer, $loop) {
+ $pending = null;
+
+ // foward unsubscribe/punsubscribe events when underlying connection closes
+ $n = count($subscribed);
+ foreach ($subscribed as $channel => $_) {
+ $self->emit('unsubscribe', array($channel, --$n));
+ }
+ $n = count($psubscribed);
+ foreach ($psubscribed as $pattern => $_) {
+ $self->emit('punsubscribe', array($pattern, --$n));
+ }
+ $subscribed = array();
+ $psubscribed = array();
+
+ if ($idleTimer !== null) {
+ $loop->cancelTimer($idleTimer);
+ $idleTimer = null;
+ }
+ });
+
+ // keep track of all channels and patterns this connection is subscribed to
+ $redis->on('subscribe', function ($channel) use (&$subscribed) {
+ $subscribed[$channel] = true;
+ });
+ $redis->on('psubscribe', function ($pattern) use (&$psubscribed) {
+ $psubscribed[$pattern] = true;
+ });
+ $redis->on('unsubscribe', function ($channel) use (&$subscribed) {
+ unset($subscribed[$channel]);
+ });
+ $redis->on('punsubscribe', function ($pattern) use (&$psubscribed) {
+ unset($psubscribed[$pattern]);
+ });
+
+ Util::forwardEvents(
+ $redis,
+ $self,
+ array(
+ 'message',
+ 'subscribe',
+ 'unsubscribe',
+ 'pmessage',
+ 'psubscribe',
+ 'punsubscribe',
+ )
+ );
+
+ return $redis;
+ }, function (\Exception $e) use (&$pending) {
+ // connection failed => discard connection attempt
+ $pending = null;
+
+ throw $e;
+ });
+ }
+
+ public function __call($name, $args)
+ {
+ if ($this->closed) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'Connection closed (ENOTCONN)',
+ defined('SOCKET_ENOTCONN') ? SOCKET_ENOTCONN : 107
+ ));
+ }
+
+ $that = $this;
+ return $this->client()->then(function (Client $redis) use ($name, $args, $that) {
+ $that->awake();
+ return \call_user_func_array(array($redis, $name), $args)->then(
+ function ($result) use ($that) {
+ $that->idle();
+ return $result;
+ },
+ function ($error) use ($that) {
+ $that->idle();
+ throw $error;
+ }
+ );
+ });
+ }
+
+ public function end()
+ {
+ if ($this->promise === null) {
+ $this->close();
+ }
+
+ if ($this->closed) {
+ return;
+ }
+
+ $that = $this;
+ return $this->client()->then(function (Client $redis) use ($that) {
+ $redis->on('close', function () use ($that) {
+ $that->close();
+ });
+ $redis->end();
+ });
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ // either close active connection or cancel pending connection attempt
+ if ($this->promise !== null) {
+ $this->promise->then(function (Client $redis) {
+ $redis->close();
+ });
+ if ($this->promise !== null) {
+ $this->promise->cancel();
+ $this->promise = null;
+ }
+ }
+
+ if ($this->idleTimer !== null) {
+ $this->loop->cancelTimer($this->idleTimer);
+ $this->idleTimer = null;
+ }
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /**
+ * @internal
+ */
+ public function awake()
+ {
+ ++$this->pending;
+
+ if ($this->idleTimer !== null) {
+ $this->loop->cancelTimer($this->idleTimer);
+ $this->idleTimer = null;
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function idle()
+ {
+ --$this->pending;
+
+ if ($this->pending < 1 && $this->idlePeriod >= 0 && !$this->subscribed && !$this->psubscribed && $this->promise !== null) {
+ $idleTimer =& $this->idleTimer;
+ $promise =& $this->promise;
+ $idleTimer = $this->loop->addTimer($this->idlePeriod, function () use (&$idleTimer, &$promise) {
+ $promise->then(function (Client $redis) {
+ $redis->close();
+ });
+ $promise = null;
+ $idleTimer = null;
+ });
+ }
+ }
+}
diff --git a/vendor/clue/redis-react/src/StreamingClient.php b/vendor/clue/redis-react/src/StreamingClient.php
new file mode 100644
index 0000000..8afd84d
--- /dev/null
+++ b/vendor/clue/redis-react/src/StreamingClient.php
@@ -0,0 +1,203 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Clue\Redis\Protocol\Factory as ProtocolFactory;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Parser\ParserException;
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Evenement\EventEmitter;
+use React\Promise\Deferred;
+use React\Stream\DuplexStreamInterface;
+
+/**
+ * @internal
+ */
+class StreamingClient extends EventEmitter implements Client
+{
+ private $stream;
+ private $parser;
+ private $serializer;
+ private $requests = array();
+ private $ending = false;
+ private $closed = false;
+
+ private $subscribed = 0;
+ private $psubscribed = 0;
+
+ public function __construct(DuplexStreamInterface $stream, ParserInterface $parser = null, SerializerInterface $serializer = null)
+ {
+ if ($parser === null || $serializer === null) {
+ $factory = new ProtocolFactory();
+ if ($parser === null) {
+ $parser = $factory->createResponseParser();
+ }
+ if ($serializer === null) {
+ $serializer = $factory->createSerializer();
+ }
+ }
+
+ $that = $this;
+ $stream->on('data', function($chunk) use ($parser, $that) {
+ try {
+ $models = $parser->pushIncoming($chunk);
+ } catch (ParserException $error) {
+ $that->emit('error', array(new \UnexpectedValueException(
+ 'Invalid data received: ' . $error->getMessage() . ' (EBADMSG)',
+ defined('SOCKET_EBADMSG') ? SOCKET_EBADMSG : 77,
+ $error
+ )));
+ $that->close();
+ return;
+ }
+
+ foreach ($models as $data) {
+ try {
+ $that->handleMessage($data);
+ } catch (\UnderflowException $error) {
+ $that->emit('error', array($error));
+ $that->close();
+ return;
+ }
+ }
+ });
+
+ $stream->on('close', array($this, 'close'));
+
+ $this->stream = $stream;
+ $this->parser = $parser;
+ $this->serializer = $serializer;
+ }
+
+ public function __call($name, $args)
+ {
+ $request = new Deferred();
+ $promise = $request->promise();
+
+ $name = strtolower($name);
+
+ // special (p)(un)subscribe commands only accept a single parameter and have custom response logic applied
+ static $pubsubs = array('subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe');
+
+ if ($this->ending) {
+ $request->reject(new \RuntimeException(
+ 'Connection ' . ($this->closed ? 'closed' : 'closing'). ' (ENOTCONN)',
+ defined('SOCKET_ENOTCONN') ? SOCKET_ENOTCONN : 107
+ ));
+ } elseif (count($args) !== 1 && in_array($name, $pubsubs)) {
+ $request->reject(new \InvalidArgumentException(
+ 'PubSub commands limited to single argument (EINVAL)',
+ defined('SOCKET_EINVAL') ? SOCKET_EINVAL : 22
+ ));
+ } elseif ($name === 'monitor') {
+ $request->reject(new \BadMethodCallException(
+ 'MONITOR command explicitly not supported (ENOTSUP)',
+ defined('SOCKET_ENOTSUP') ? SOCKET_ENOTSUP : (defined('SOCKET_EOPNOTSUPP') ? SOCKET_EOPNOTSUPP : 95)
+ ));
+ } else {
+ $this->stream->write($this->serializer->getRequestMessage($name, $args));
+ $this->requests []= $request;
+ }
+
+ if (in_array($name, $pubsubs)) {
+ $that = $this;
+ $subscribed =& $this->subscribed;
+ $psubscribed =& $this->psubscribed;
+
+ $promise->then(function ($array) use ($that, &$subscribed, &$psubscribed) {
+ $first = array_shift($array);
+
+ // (p)(un)subscribe messages are to be forwarded
+ $that->emit($first, $array);
+
+ // remember number of (p)subscribe topics
+ if ($first === 'subscribe' || $first === 'unsubscribe') {
+ $subscribed = $array[1];
+ } else {
+ $psubscribed = $array[1];
+ }
+ });
+ }
+
+ return $promise;
+ }
+
+ public function handleMessage(ModelInterface $message)
+ {
+ if (($this->subscribed !== 0 || $this->psubscribed !== 0) && $message instanceof MultiBulkReply) {
+ $array = $message->getValueNative();
+ $first = array_shift($array);
+
+ // pub/sub messages are to be forwarded and should not be processed as request responses
+ if (in_array($first, array('message', 'pmessage'))) {
+ $this->emit($first, $array);
+ return;
+ }
+ }
+
+ if (!$this->requests) {
+ throw new \UnderflowException(
+ 'Unexpected reply received, no matching request found (ENOMSG)',
+ defined('SOCKET_ENOMSG') ? SOCKET_ENOMSG : 42
+ );
+ }
+
+ $request = array_shift($this->requests);
+ assert($request instanceof Deferred);
+
+ if ($message instanceof ErrorReply) {
+ $request->reject($message);
+ } else {
+ $request->resolve($message->getValueNative());
+ }
+
+ if ($this->ending && !$this->requests) {
+ $this->close();
+ }
+ }
+
+ public function end()
+ {
+ $this->ending = true;
+
+ if (!$this->requests) {
+ $this->close();
+ }
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->ending = true;
+ $this->closed = true;
+
+ $remoteClosed = $this->stream->isReadable() === false && $this->stream->isWritable() === false;
+ $this->stream->close();
+
+ $this->emit('close');
+
+ // reject all remaining requests in the queue
+ while ($this->requests) {
+ $request = array_shift($this->requests);
+ assert($request instanceof Deferred);
+
+ if ($remoteClosed) {
+ $request->reject(new \RuntimeException(
+ 'Connection closed by peer (ECONNRESET)',
+ defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104
+ ));
+ } else {
+ $request->reject(new \RuntimeException(
+ 'Connection closing (ECONNABORTED)',
+ defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
+ ));
+ }
+ }
+ }
+}
diff --git a/vendor/clue/soap-react/LICENSE b/vendor/clue/soap-react/LICENSE
new file mode 100644
index 0000000..9426ad3
--- /dev/null
+++ b/vendor/clue/soap-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Christian Lück
+
+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/clue/soap-react/composer.json b/vendor/clue/soap-react/composer.json
new file mode 100644
index 0000000..3b7fc4a
--- /dev/null
+++ b/vendor/clue/soap-react/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "clue/soap-react",
+ "description": "Simple, async SOAP webservice client library, built on top of ReactPHP",
+ "keywords": ["SOAP", "SoapClient", "WebService", "WSDL", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-soap",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\Soap\\": "src/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "clue/buzz-react": "^2.5",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2",
+ "ext-soap": "*"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/clue/soap-react/src/Client.php b/vendor/clue/soap-react/src/Client.php
new file mode 100644
index 0000000..85ee7af
--- /dev/null
+++ b/vendor/clue/soap-react/src/Client.php
@@ -0,0 +1,323 @@
+<?php
+
+namespace Clue\React\Soap;
+
+use Clue\React\Buzz\Browser;
+use Clue\React\Soap\Protocol\ClientDecoder;
+use Clue\React\Soap\Protocol\ClientEncoder;
+use Psr\Http\Message\ResponseInterface;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+
+/**
+ * The `Client` class is responsible for communication with the remote SOAP
+ * WebService server.
+ *
+ * It requires a [`Browser`](https://github.com/clue/reactphp-buzz#browser) object
+ * bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
+ * in order to handle async requests, the WSDL file contents and an optional
+ * array of SOAP options:
+ *
+ * ```php
+ * $loop = React\EventLoop\Factory::create();
+ * $browser = new Clue\React\Buzz\Browser($loop);
+ *
+ * $wsdl = '<?xml …';
+ * $options = array();
+ *
+ * $client = new Client($browser, $wsdl, $options);
+ * ```
+ *
+ * If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
+ * proxy servers etc.), you can explicitly pass a custom instance of the
+ * [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
+ * to the [`Browser`](https://github.com/clue/reactphp-buzz#browser) instance:
+ *
+ * ```php
+ * $connector = new \React\Socket\Connector($loop, array(
+ * 'dns' => '127.0.0.1',
+ * 'tcp' => array(
+ * 'bindto' => '192.168.10.1:0'
+ * ),
+ * 'tls' => array(
+ * 'verify_peer' => false,
+ * 'verify_peer_name' => false
+ * )
+ * ));
+ *
+ * $browser = new Browser($loop, $connector);
+ * $client = new Client($browser, $wsdl);
+ * ```
+ *
+ * The `Client` works similar to PHP's `SoapClient` (which it uses under the
+ * hood), but leaves you the responsibility to load the WSDL file. This allows
+ * you to use local WSDL files, WSDL files from a cache or the most common form,
+ * downloading the WSDL file contents from an URL through the `Browser`:
+ *
+ * ```php
+ * $browser = new Browser($loop);
+ *
+ * $browser->get($url)->then(
+ * function (ResponseInterface $response) use ($browser) {
+ * // WSDL file is ready, create client
+ * $client = new Client($browser, (string)$response->getBody());
+ *
+ * // do something…
+ * },
+ * function (Exception $e) {
+ * // an error occured while trying to download the WSDL
+ * }
+ * );
+ * ```
+ *
+ * The `Client` constructor loads the given WSDL file contents into memory and
+ * parses its definition. If the given WSDL file is invalid and can not be
+ * parsed, this will throw a `SoapFault`:
+ *
+ * ```php
+ * try {
+ * $client = new Client($browser, $wsdl);
+ * } catch (SoapFault $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * }
+ * ```
+ *
+ * > Note that if you have `ext-xdebug` loaded, this may halt with a fatal
+ * error instead of throwing a `SoapFault`. It is not recommended to use this
+ * extension in production, so this should only ever affect test environments.
+ *
+ * The `Client` constructor accepts an array of options. All given options will
+ * be passed through to the underlying `SoapClient`. However, not all options
+ * make sense in this async implementation and as such may not have the desired
+ * effect. See also [`SoapClient`](http://php.net/manual/en/soapclient.soapclient.php)
+ * documentation for more details.
+ *
+ * If working in WSDL mode, the `$options` parameter is optional. If working in
+ * non-WSDL mode, the WSDL parameter must be set to `null` and the options
+ * parameter must contain the `location` and `uri` options, where `location` is
+ * the URL of the SOAP server to send the request to, and `uri` is the target
+ * namespace of the SOAP service:
+ *
+ * ```php
+ * $client = new Client($browser, null, array(
+ * 'location' => 'http://example.com',
+ * 'uri' => 'http://ping.example.com',
+ * ));
+ * ```
+ *
+ * Similarly, if working in WSDL mode, the `location` option can be used to
+ * explicitly overwrite the URL of the SOAP server to send the request to:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'location' => 'http://example.com'
+ * ));
+ * ```
+ *
+ * You can use the `soap_version` option to change from the default SOAP 1.1 to
+ * use SOAP 1.2 instead:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'soap_version' => SOAP_1_2
+ * ));
+ * ```
+ *
+ * You can use the `classmap` option to map certain WSDL types to PHP classes
+ * like this:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'classmap' => array(
+ * 'getBankResponseType' => BankResponse::class
+ * )
+ * ));
+ * ```
+ *
+ * The `proxy_host` option (and family) is not supported by this library. As an
+ * alternative, you can configure the given `$browser` instance to use an
+ * [HTTP proxy server](https://github.com/clue/reactphp-buzz#http-proxy).
+ * If you find any other option is missing or not supported here, PRs are much
+ * appreciated!
+ *
+ * All public methods of the `Client` are considered *advanced usage*.
+ * If you want to call RPC functions, see below for the [`Proxy`](#proxy) class.
+ */
+class Client
+{
+ private $browser;
+ private $encoder;
+ private $decoder;
+
+ /**
+ * Instantiate a new SOAP client for the given WSDL contents.
+ *
+ * @param Browser $browser
+ * @param string|null $wsdlContents
+ * @param array $options
+ */
+ public function __construct(Browser $browser, $wsdlContents, array $options = array())
+ {
+ $wsdl = $wsdlContents !== null ? 'data://text/plain;base64,' . base64_encode($wsdlContents) : null;
+
+ // Accept HTTP responses with error status codes as valid responses.
+ // This is done in order to process these error responses through the normal SOAP decoder.
+ // Additionally, we explicitly limit number of redirects to zero because following redirects makes little sense
+ // because it transforms the POST request to a GET one and hence loses the SOAP request body.
+ $browser = $browser->withOptions(array(
+ 'obeySuccessCode' => false,
+ 'followRedirects' => true,
+ 'maxRedirects' => 0
+ ));
+
+ $this->browser = $browser;
+ $this->encoder = new ClientEncoder($wsdl, $options);
+ $this->decoder = new ClientDecoder($wsdl, $options);
+ }
+
+ /**
+ * Queue the given function to be sent via SOAP and wait for a response from the remote web service.
+ *
+ * ```php
+ * // advanced usage, see Proxy for recommended alternative
+ * $promise = $client->soapCall('ping', array('hello', 42));
+ * ```
+ *
+ * Note: This is considered *advanced usage*, you may want to look into using the [`Proxy`](#proxy) instead.
+ *
+ * ```php
+ * $proxy = new Proxy($client);
+ * $promise = $proxy->ping('hello', 42);
+ * ```
+ *
+ * @param string $name
+ * @param mixed[] $args
+ * @return PromiseInterface Returns a Promise<mixed, Exception>
+ */
+ public function soapCall($name, $args)
+ {
+ try {
+ $request = $this->encoder->encode($name, $args);
+ } catch (\Exception $e) {
+ $deferred = new Deferred();
+ $deferred->reject($e);
+ return $deferred->promise();
+ }
+
+ $decoder = $this->decoder;
+
+ return $this->browser->send($request)->then(
+ function (ResponseInterface $response) use ($decoder, $name) {
+ // HTTP response received => decode results for this function call
+ return $decoder->decode($name, (string)$response->getBody());
+ }
+ );
+ }
+
+ /**
+ * Returns an array of functions defined in the WSDL.
+ *
+ * It returns the equivalent of PHP's
+ * [`SoapClient::__getFunctions()`](http://php.net/manual/en/soapclient.getfunctions.php).
+ * In non-WSDL mode, this method returns `null`.
+ *
+ * @return string[]|null
+ */
+ public function getFunctions()
+ {
+ return $this->encoder->__getFunctions();
+ }
+
+ /**
+ * Returns an array of types defined in the WSDL.
+ *
+ * It returns the equivalent of PHP's
+ * [`SoapClient::__getTypes()`](http://php.net/manual/en/soapclient.gettypes.php).
+ * In non-WSDL mode, this method returns `null`.
+ *
+ * @return string[]|null
+ */
+ public function getTypes()
+ {
+ return $this->encoder->__getTypes();
+ }
+
+ /**
+ * Returns the location (URI) of the given webservice `$function`.
+ *
+ * Note that this is not to be confused with the WSDL file location.
+ * A WSDL file can contain any number of function definitions.
+ * It's very common that all of these functions use the same location definition.
+ * However, technically each function can potentially use a different location.
+ *
+ * The `$function` parameter should be a string with the the SOAP function name.
+ * See also [`getFunctions()`](#getfunctions) for a list of all available functions.
+ *
+ * ```php
+ * assert('http://example.com/soap/service' === $client->getLocation('echo'));
+ * ```
+ *
+ * For easier access, this function also accepts a numeric function index.
+ * It then uses [`getFunctions()`](#getfunctions) internally to get the function
+ * name for the given index.
+ * This is particularly useful for the very common case where all functions use the
+ * same location and accessing the first location is sufficient.
+ *
+ * ```php
+ * assert('http://example.com/soap/service' === $client->getLocation(0));
+ * ```
+ *
+ * When the `location` option has been set in the `Client` constructor
+ * (such as when in non-WSDL mode) or via the `withLocation()` method, this
+ * method returns the value of the given location.
+ *
+ * Passing a `$function` not defined in the WSDL file will throw a `SoapFault`.
+ *
+ * @param string|int $function
+ * @return string
+ * @throws \SoapFault if given function does not exist
+ * @see self::getFunctions()
+ */
+ public function getLocation($function)
+ {
+ if (is_int($function)) {
+ $functions = $this->getFunctions();
+ if (isset($functions[$function]) && preg_match('/^\w+ (\w+)\(/', $functions[$function], $match)) {
+ $function = $match[1];
+ }
+ }
+
+ // encode request for given $function
+ return (string)$this->encoder->encode($function, array())->getUri();
+ }
+
+ /**
+ * Returns a new `Client` with the updated location (URI) for all functions.
+ *
+ * Note that this is not to be confused with the WSDL file location.
+ * A WSDL file can contain any number of function definitions.
+ * It's very common that all of these functions use the same location definition.
+ * However, technically each function can potentially use a different location.
+ *
+ * ```php
+ * $client = $client->withLocation('http://example.com/soap');
+ *
+ * assert('http://example.com/soap' === $client->getLocation('echo'));
+ * ```
+ *
+ * As an alternative to this method, you can also set the `location` option
+ * in the `Client` constructor (such as when in non-WSDL mode).
+ *
+ * @param string $location
+ * @return self
+ * @see self::getLocation()
+ */
+ public function withLocation($location)
+ {
+ $client = clone $this;
+ $client->encoder = clone $this->encoder;
+ $client->encoder->__setLocation($location);
+
+ return $client;
+ }
+}
diff --git a/vendor/clue/soap-react/src/Protocol/ClientDecoder.php b/vendor/clue/soap-react/src/Protocol/ClientDecoder.php
new file mode 100644
index 0000000..39cb745
--- /dev/null
+++ b/vendor/clue/soap-react/src/Protocol/ClientDecoder.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Clue\React\Soap\Protocol;
+
+use \SoapClient;
+
+/**
+ * @internal
+ */
+final class ClientDecoder extends SoapClient
+{
+ private $response = null;
+
+ /**
+ * Decodes the SOAP response / return value from the given SOAP envelope (HTTP response body)
+ *
+ * @param string $function
+ * @param string $response
+ * @return mixed
+ * @throws \SoapFault if response indicates a fault (error condition) or is invalid
+ */
+ public function decode($function, $response)
+ {
+ // Temporarily save response internally for further processing
+ $this->response = $response;
+
+ // Let's pretend we just invoked the given SOAP function.
+ // This won't actually invoke anything (see `__doRequest()`), but this
+ // requires a valid function name to match its definition in the WSDL.
+ // Internally, simply use the injected response to parse its results.
+ $ret = $this->__soapCall($function, array());
+ $this->response = null;
+
+ return $ret;
+ }
+
+ /**
+ * Overwrites the internal request logic to parse the response
+ *
+ * By overwriting this method, we can skip the actual request sending logic
+ * and still use the internal parsing logic by injecting the response as
+ * the return code in this method. This will implicitly be invoked by the
+ * call to `pseudoCall()` in the above `decode()` method.
+ *
+ * @see SoapClient::__doRequest()
+ */
+ public function __doRequest($request, $location, $action, $version, $one_way = 0)
+ {
+ // the actual result doesn't actually matter, just return the given result
+ // this will be processed internally and will return the parsed result
+ return $this->response;
+ }
+}
diff --git a/vendor/clue/soap-react/src/Protocol/ClientEncoder.php b/vendor/clue/soap-react/src/Protocol/ClientEncoder.php
new file mode 100644
index 0000000..e9d0018
--- /dev/null
+++ b/vendor/clue/soap-react/src/Protocol/ClientEncoder.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Clue\React\Soap\Protocol;
+
+use \SoapClient;
+use RingCentral\Psr7\Request;
+
+/**
+ * @internal
+ */
+final class ClientEncoder extends SoapClient
+{
+ private $request = null;
+
+ /**
+ * Encodes the given RPC function name and arguments as a SOAP request
+ *
+ * @param string $name
+ * @param array $args
+ * @return Request
+ * @throws \SoapFault if request is invalid according to WSDL
+ */
+ public function encode($name, $args)
+ {
+ $this->__soapCall($name, $args);
+
+ $request = $this->request;
+ $this->request = null;
+
+ return $request;
+ }
+
+ /**
+ * Overwrites the internal request logic to build the request message
+ *
+ * By overwriting this method, we can skip the actual request sending logic
+ * and still use the internal request serializing logic by accessing the
+ * given `$request` parameter and building our custom request object from
+ * it. We skip/ignore its parsing logic by returing an empty response here.
+ * This will implicitly be invoked by the call to `__soapCall()` in the
+ * above `encode()` method.
+ *
+ * @see SoapClient::__doRequest()
+ */
+ public function __doRequest($request, $location, $action, $version, $one_way = 0)
+ {
+ $headers = array();
+ if ($version === SOAP_1_1) {
+ $headers = array(
+ 'SOAPAction' => $action,
+ 'Content-Type' => 'text/xml; charset=utf-8'
+ );
+ } elseif ($version === SOAP_1_2) {
+ $headers = array(
+ 'Content-Type' => 'application/soap+xml; charset=utf-8; action=' . $action
+ );
+ }
+
+ $this->request = new Request(
+ 'POST',
+ (string)$location,
+ $headers,
+ (string)$request
+ );
+
+ // do not actually block here, just pretend we're done...
+ return '';
+ }
+}
diff --git a/vendor/clue/soap-react/src/Proxy.php b/vendor/clue/soap-react/src/Proxy.php
new file mode 100644
index 0000000..06d70a0
--- /dev/null
+++ b/vendor/clue/soap-react/src/Proxy.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Clue\React\Soap;
+
+use React\Promise\PromiseInterface;
+
+/**
+ * The `Proxy` class wraps an existing [`Client`](#client) instance in order to ease calling
+ * SOAP functions.
+ *
+ * ```php
+ * $proxy = new Proxy($client);
+ * ```
+ *
+ * Each and every method call to the `Proxy` class will be sent via SOAP.
+ *
+ * ```php
+ * $proxy->myMethod($myArg1, $myArg2)->then(function ($response) {
+ * // result received
+ * });
+ * ```
+ *
+ * Please refer to your WSDL or its accompanying documentation for details
+ * on which functions and arguments are supported.
+ *
+ * > Note that this class is called "Proxy" because it will forward (proxy) all
+ * method calls to the actual SOAP service via the underlying
+ * [`Client::soapCall()`](#soapcall) method. This is not to be confused with
+ * using a proxy server. See [`Client`](#client) documentation for more
+ * details on how to use an HTTP proxy server.
+ */
+final class Proxy
+{
+ private $client;
+
+ public function __construct(Client $client)
+ {
+ $this->client = $client;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed[] $args
+ * @return PromiseInterface
+ */
+ public function __call($name, $args)
+ {
+ return $this->client->soapCall($name, $args);
+ }
+}
diff --git a/vendor/clue/socket-raw/LICENSE b/vendor/clue/socket-raw/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/socket-raw/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+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/clue/socket-raw/composer.json b/vendor/clue/socket-raw/composer.json
new file mode 100644
index 0000000..2add27e
--- /dev/null
+++ b/vendor/clue/socket-raw/composer.json
@@ -0,0 +1,23 @@
+{
+ "name": "clue/socket-raw",
+ "description": "Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets).",
+ "keywords": ["socket", "stream", "datagram", "dgram", "client", "server", "ipv6", "tcp", "udp", "icmp", "unix", "udg"],
+ "homepage": "https://github.com/clue/socket-raw",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": {"Socket\\Raw\\": "src"}
+ },
+ "require": {
+ "ext-sockets": "*",
+ "php": ">=5.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/clue/socket-raw/src/Exception.php b/vendor/clue/socket-raw/src/Exception.php
new file mode 100644
index 0000000..bdabf78
--- /dev/null
+++ b/vendor/clue/socket-raw/src/Exception.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Socket\Raw;
+
+use RuntimeException;
+
+class Exception extends RuntimeException
+{
+ /**
+ * Create an Exception after a socket operation on the given $resource failed
+ *
+ * @param \Socket|resource $resource
+ * @param string $messagePrefix
+ * @return self
+ * @uses socket_last_error() to get last socket error code
+ * @uses socket_clear_error() to clear socket error code
+ * @uses self::createFromCode() to automatically construct exception with full error message
+ */
+ public static function createFromSocketResource($resource, $messagePrefix = 'Socket operation failed')
+ {
+ if (PHP_VERSION_ID >= 80000) {
+ try {
+ $code = socket_last_error($resource);
+ } catch (\Error $e) {
+ $code = SOCKET_ENOTSOCK;
+ }
+ } elseif (is_resource($resource)) {
+ $code = socket_last_error($resource);
+ socket_clear_error($resource);
+ } else {
+ // socket already closed, return fixed error code instead of operating on invalid handle
+ $code = SOCKET_ENOTSOCK;
+ }
+
+ return self::createFromCode($code, $messagePrefix);
+ }
+
+ /**
+ * Create an Exception after a global socket operation failed (like socket creation)
+ *
+ * @param string $messagePrefix
+ * @return self
+ * @uses socket_last_error() to get last global error code
+ * @uses socket_clear_error() to clear global error code
+ * @uses self::createFromCode() to automatically construct exception with full error message
+ */
+ public static function createFromGlobalSocketOperation($messagePrefix = 'Socket operation failed')
+ {
+ $code = socket_last_error();
+ socket_clear_error();
+
+ return self::createFromCode($code, $messagePrefix);
+ }
+
+ /**
+ * Create an Exception for given error $code
+ *
+ * @param int $code
+ * @param string $messagePrefix
+ * @return self
+ * @throws Exception if given $val is boolean false
+ * @uses self::getErrorMessage() to translate error code to error message
+ */
+ public static function createFromCode($code, $messagePrefix = 'Socket error')
+ {
+ return new self($messagePrefix . ': ' . self::getErrorMessage($code), $code);
+ }
+
+ /**
+ * get error message for given error code
+ *
+ * @param int $code error code
+ * @return string
+ * @uses socket_strerror() to translate error code to error message
+ * @uses get_defined_constants() to check for related error constant
+ */
+ protected static function getErrorMessage($code)
+ {
+ $string = socket_strerror($code);
+
+ // search constant starting with SOCKET_ for this error code
+ foreach (get_defined_constants() as $key => $value) {
+ if($value === $code && strpos($key, 'SOCKET_') === 0) {
+ $string .= ' (' . $key . ')';
+ break;
+ }
+ }
+
+ return $string;
+ }
+}
diff --git a/vendor/clue/socket-raw/src/Factory.php b/vendor/clue/socket-raw/src/Factory.php
new file mode 100644
index 0000000..a5068f9
--- /dev/null
+++ b/vendor/clue/socket-raw/src/Factory.php
@@ -0,0 +1,282 @@
+<?php
+
+namespace Socket\Raw;
+
+use \InvalidArgumentException;
+
+class Factory
+{
+ /**
+ * create client socket connected to given target address
+ *
+ * @param string $address target address to connect to
+ * @param null|float $timeout connection timeout (in seconds), default null = no limit
+ * @return \Socket\Raw\Socket
+ * @throws InvalidArgumentException if given address is invalid
+ * @throws Exception on error
+ * @uses self::createFromString()
+ * @uses Socket::connect()
+ * @uses Socket::connectTimeout()
+ */
+ public function createClient($address, $timeout = null)
+ {
+ $socket = $this->createFromString($address, $scheme);
+
+ try {
+ if ($timeout === null) {
+ $socket->connect($address);
+ } else {
+ // connectTimeout enables non-blocking mode, so turn blocking on again
+ $socket->connectTimeout($address, $timeout);
+ $socket->setBlocking(true);
+ }
+ } catch (Exception $e) {
+ $socket->close();
+ throw $e;
+ }
+
+ return $socket;
+ }
+
+ /**
+ * create server socket bound to given address (and start listening for streaming clients to connect to this stream socket)
+ *
+ * @param string $address address to bind socket to
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::createFromString()
+ * @uses Socket::bind()
+ * @uses Socket::listen() only for stream sockets (TCP/UNIX)
+ */
+ public function createServer($address)
+ {
+ $socket = $this->createFromString($address, $scheme);
+
+ try {
+ $socket->bind($address);
+
+ if ($socket->getType() === SOCK_STREAM) {
+ $socket->listen();
+ }
+ } catch (Exception $e) {
+ $socket->close();
+ throw $e;
+ }
+
+ return $socket;
+ }
+
+ /**
+ * create TCP/IPv4 stream socket
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createTcp4()
+ {
+ return $this->create(AF_INET, SOCK_STREAM, SOL_TCP);
+ }
+
+ /**
+ * create TCP/IPv6 stream socket
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createTcp6()
+ {
+ return $this->create(AF_INET6, SOCK_STREAM, SOL_TCP);
+ }
+
+ /**
+ * create UDP/IPv4 datagram socket
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createUdp4()
+ {
+ return $this->create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ }
+
+ /**
+ * create UDP/IPv6 datagram socket
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createUdp6()
+ {
+ return $this->create(AF_INET6, SOCK_DGRAM, SOL_UDP);
+ }
+
+ /**
+ * create local UNIX stream socket
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createUnix()
+ {
+ return $this->create(AF_UNIX, SOCK_STREAM, 0);
+ }
+
+ /**
+ * create local UNIX datagram socket (UDG)
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createUdg()
+ {
+ return $this->create(AF_UNIX, SOCK_DGRAM, 0);
+ }
+
+ /**
+ * create raw ICMP/IPv4 datagram socket (requires root!)
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createIcmp4()
+ {
+ return $this->create(AF_INET, SOCK_RAW, getprotobyname('icmp'));
+ }
+
+ /**
+ * create raw ICMPv6 (IPv6) datagram socket (requires root!)
+ *
+ * @return \Socket\Raw\Socket
+ * @throws Exception on error
+ * @uses self::create()
+ */
+ public function createIcmp6()
+ {
+ return $this->create(AF_INET6, SOCK_RAW, 58 /*getprotobyname('icmp')*/);
+ }
+
+ /**
+ * create low level socket with given arguments
+ *
+ * @param int $domain
+ * @param int $type
+ * @param int $protocol
+ * @return \Socket\Raw\Socket
+ * @throws Exception if creating socket fails
+ * @throws \Error PHP 8 only: throws \Error when arguments are invalid
+ * @uses socket_create()
+ */
+ public function create($domain, $type, $protocol)
+ {
+ $sock = @socket_create($domain, $type, $protocol);
+ if ($sock === false) {
+ throw Exception::createFromGlobalSocketOperation('Unable to create socket');
+ }
+ return new Socket($sock);
+ }
+
+ /**
+ * create a pair of indistinguishable sockets (commonly used in IPC)
+ *
+ * @param int $domain
+ * @param int $type
+ * @param int $protocol
+ * @return \Socket\Raw\Socket[]
+ * @throws Exception if creating pair of sockets fails
+ * @throws \Error PHP 8 only: throws \Error when arguments are invalid
+ * @uses socket_create_pair()
+ */
+ public function createPair($domain, $type, $protocol)
+ {
+ $ret = @socket_create_pair($domain, $type, $protocol, $pair);
+ if ($ret === false) {
+ throw Exception::createFromGlobalSocketOperation('Unable to create pair of sockets');
+ }
+ return array(new Socket($pair[0]), new Socket($pair[1]));
+ }
+
+ /**
+ * create TCP/IPv4 stream socket and listen for new connections
+ *
+ * @param int $port
+ * @param int $backlog
+ * @return \Socket\Raw\Socket
+ * @throws Exception if creating listening socket fails
+ * @throws \Error PHP 8 only: throws \Error when arguments are invalid
+ * @uses socket_create_listen()
+ * @see self::createServer() as an alternative to bind to specific IP, IPv6, UDP, UNIX, UGP
+ */
+ public function createListen($port, $backlog = 128)
+ {
+ $sock = @socket_create_listen($port, $backlog);
+ if ($sock === false) {
+ throw Exception::createFromGlobalSocketOperation('Unable to create listening socket');
+ }
+ return new Socket($sock);
+ }
+
+ /**
+ * create socket for given address
+ *
+ * @param string $address (passed by reference in order to remove scheme, if present)
+ * @param string|null $scheme default scheme to use, defaults to TCP (passed by reference in order to update with actual scheme used)
+ * @return \Socket\Raw\Socket
+ * @throws InvalidArgumentException if given address is invalid
+ * @throws Exception in case creating socket failed
+ * @uses self::createTcp4() etc.
+ */
+ public function createFromString(&$address, &$scheme)
+ {
+ if ($scheme === null) {
+ $scheme = 'tcp';
+ }
+
+ $hasScheme = false;
+
+ $pos = strpos($address, '://');
+ if ($pos !== false) {
+ $scheme = substr($address, 0, $pos);
+ $address = substr($address, $pos + 3);
+ $hasScheme = true;
+ }
+
+ if (strpos($address, ':') !== strrpos($address, ':') && in_array($scheme, array('tcp', 'udp', 'icmp'))) {
+ // TCP/UDP/ICMP address with several colons => must be IPv6
+ $scheme .= '6';
+ }
+
+ if ($scheme === 'tcp') {
+ $socket = $this->createTcp4();
+ } elseif ($scheme === 'udp') {
+ $socket = $this->createUdp4();
+ } elseif ($scheme === 'tcp6') {
+ $socket = $this->createTcp6();
+ } elseif ($scheme === 'udp6') {
+ $socket = $this->createUdp6();
+ } elseif ($scheme === 'unix') {
+ $socket = $this->createUnix();
+ } elseif ($scheme === 'udg') {
+ $socket = $this->createUdg();
+ } elseif ($scheme === 'icmp') {
+ $socket = $this->createIcmp4();
+ } elseif ($scheme === 'icmp6') {
+ $socket = $this->createIcmp6();
+ if ($hasScheme) {
+ // scheme was stripped from address, resulting IPv6 must not
+ // have a port (due to ICMP) and thus must not be enclosed in
+ // square brackets
+ $address = trim($address, '[]');
+ }
+ } else {
+ throw new InvalidArgumentException('Invalid address scheme given');
+ }
+ return $socket;
+ }
+}
diff --git a/vendor/clue/socket-raw/src/Socket.php b/vendor/clue/socket-raw/src/Socket.php
new file mode 100644
index 0000000..67407f2
--- /dev/null
+++ b/vendor/clue/socket-raw/src/Socket.php
@@ -0,0 +1,562 @@
+<?php
+
+namespace Socket\Raw;
+
+/**
+ * Simple and lightweight OOP wrapper for the low-level sockets extension (ext-sockets)
+ *
+ * @author clue
+ * @link https://github.com/clue/php-socket-raw
+ */
+class Socket
+{
+ /**
+ * reference to actual socket resource
+ *
+ * @var \Socket|resource
+ */
+ private $resource;
+
+ /**
+ * instanciate socket wrapper for given socket resource
+ *
+ * should usually not be called manually, see Factory
+ *
+ * @param \Socket|resource $resource
+ * @see Factory as the preferred (and simplest) way to construct socket instances
+ */
+ public function __construct($resource)
+ {
+ $this->resource = $resource;
+ }
+
+ /**
+ * get actual socket resource
+ *
+ * @return \Socket|resource returns the socket resource (a `Socket` object as of PHP 8)
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * accept an incomming connection on this listening socket
+ *
+ * @return \Socket\Raw\Socket new connected socket used for communication
+ * @throws Exception on error, if this is not a listening socket or there's no connection pending
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @see self::selectRead() to check if this listening socket can accept()
+ * @see Factory::createServer() to create a listening socket
+ * @see self::listen() has to be called first
+ * @uses socket_accept()
+ */
+ public function accept()
+ {
+ $resource = @socket_accept($this->resource);
+ if ($resource === false) {
+ throw Exception::createFromGlobalSocketOperation();
+ }
+ return new Socket($resource);
+ }
+
+ /**
+ * binds a name/address/path to this socket
+ *
+ * has to be called before issuing connect() or listen()
+ *
+ * @param string $address either of IPv4:port, hostname:port, [IPv6]:port, unix-path
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_bind()
+ */
+ public function bind($address)
+ {
+ $ret = @socket_bind($this->resource, $this->unformatAddress($address, $port), $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * close this socket
+ *
+ * ATTENTION: make sure to NOT re-use this socket instance after closing it!
+ * its socket resource remains closed and most further operations will fail!
+ *
+ * @return self $this (chainable)
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @see self::shutdown() should be called before closing socket
+ * @uses socket_close()
+ */
+ public function close()
+ {
+ socket_close($this->resource);
+ return $this;
+ }
+
+ /**
+ * initiate a connection to given address
+ *
+ * @param string $address either of IPv4:port, hostname:port, [IPv6]:port, unix-path
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_connect()
+ */
+ public function connect($address)
+ {
+ $ret = @socket_connect($this->resource, $this->unformatAddress($address, $port), $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * Initiates a new connection to given address, wait for up to $timeout seconds
+ *
+ * The given $timeout parameter is an upper bound, a maximum time to wait
+ * for the connection to be either accepted or rejected.
+ *
+ * The resulting socket resource will be set to non-blocking mode,
+ * regardless of its previous state and whether this method succedes or
+ * if it fails. Make sure to reset with `setBlocking(true)` if you want to
+ * continue using blocking calls.
+ *
+ * @param string $address either of IPv4:port, hostname:port, [IPv6]:port, unix-path
+ * @param float $timeout maximum time to wait (in seconds)
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses self::setBlocking() to enable non-blocking mode
+ * @uses self::connect() to initiate the connection
+ * @uses self::selectWrite() to wait for the connection to complete
+ * @uses self::assertAlive() to check connection state
+ */
+ public function connectTimeout($address, $timeout)
+ {
+ $this->setBlocking(false);
+
+ try {
+ // socket is non-blocking, so connect should emit EINPROGRESS
+ $this->connect($address);
+
+ // socket is already connected immediately?
+ return $this;
+ } catch (Exception $e) {
+ // non-blocking connect() should be EINPROGRESS (or EWOULDBLOCK on Windows) => otherwise re-throw
+ if ($e->getCode() !== SOCKET_EINPROGRESS && $e->getCode() !== SOCKET_EWOULDBLOCK) {
+ throw $e;
+ }
+
+ // connection should be completed (or rejected) within timeout: socket becomes writable on success or error
+ // Windows requires special care because it uses exceptfds for socket errors: https://github.com/reactphp/event-loop/issues/206
+ $r = null;
+ $w = array($this->resource);
+ $e = DIRECTORY_SEPARATOR === '\\' ? $w : null;
+ $ret = @socket_select($r, $w, $e, $timeout === null ? null : (int) $timeout, (int) (($timeout - floor($timeout)) * 1000000));
+
+ if ($ret === false) {
+ throw Exception::createFromGlobalSocketOperation('Failed to select socket for writing');
+ } elseif ($ret === 0) {
+ throw new Exception('Timed out while waiting for connection', SOCKET_ETIMEDOUT);
+ }
+
+ // confirm connection success (or fail if connected has been rejected)
+ $this->assertAlive();
+
+ return $this;
+ }
+ }
+
+ /**
+ * get socket option
+ *
+ * @param int $level
+ * @param int $optname
+ * @return mixed
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_get_option()
+ */
+ public function getOption($level, $optname)
+ {
+ $value = @socket_get_option($this->resource, $level, $optname);
+ if ($value === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $value;
+ }
+
+ /**
+ * get remote side's address/path
+ *
+ * @return string
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @uses socket_getpeername()
+ */
+ public function getPeerName()
+ {
+ $ret = @socket_getpeername($this->resource, $address, $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this->formatAddress($address, $port);
+ }
+
+ /**
+ * get local side's address/path
+ *
+ * @return string
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @uses socket_getsockname()
+ */
+ public function getSockName()
+ {
+ $ret = @socket_getsockname($this->resource, $address, $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this->formatAddress($address, $port);
+ }
+
+ /**
+ * start listen for incoming connections
+ *
+ * @param int $backlog maximum number of incoming connections to be queued
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::bind() has to be called first to bind name to socket
+ * @uses socket_listen()
+ */
+ public function listen($backlog = 0)
+ {
+ $ret = @socket_listen($this->resource, $backlog);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * read up to $length bytes from connect()ed / accept()ed socket
+ *
+ * The $type parameter specifies if this should use either binary safe reading
+ * (PHP_BINARY_READ, the default) or stop at CR or LF characters (PHP_NORMAL_READ)
+ *
+ * @param int $length maximum length to read
+ * @param int $type either of PHP_BINARY_READ (the default) or PHP_NORMAL_READ
+ * @return string
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::recv() if you need to pass flags
+ * @uses socket_read()
+ */
+ public function read($length, $type = PHP_BINARY_READ)
+ {
+ $data = @socket_read($this->resource, $length, $type);
+ if ($data === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $data;
+ }
+
+ /**
+ * receive up to $length bytes from connect()ed / accept()ed socket
+ *
+ * @param int $length maximum length to read
+ * @param int $flags
+ * @return string
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::read() if you do not need to pass $flags
+ * @see self::recvFrom() if your socket is not connect()ed
+ * @uses socket_recv()
+ */
+ public function recv($length, $flags)
+ {
+ $ret = @socket_recv($this->resource, $buffer, $length, $flags);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $buffer;
+ }
+
+ /**
+ * receive up to $length bytes from socket
+ *
+ * @param int $length maximum length to read
+ * @param int $flags
+ * @param string $remote reference will be filled with remote/peer address/path
+ * @return string
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::recv() if your socket is connect()ed
+ * @uses socket_recvfrom()
+ */
+ public function recvFrom($length, $flags, &$remote)
+ {
+ $ret = @socket_recvfrom($this->resource, $buffer, $length, $flags, $address, $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ $remote = $this->formatAddress($address, $port);
+ return $buffer;
+ }
+
+ /**
+ * check socket to see if a read/recv/revFrom will not block
+ *
+ * @param float|null $sec maximum time to wait (in seconds), 0 = immediate polling, null = no limit
+ * @return boolean true = socket ready (read will not block), false = timeout expired, socket is not ready
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_select()
+ */
+ public function selectRead($sec = 0)
+ {
+ $usec = $sec === null ? 0 : (int) (($sec - floor($sec)) * 1000000);
+ $r = array($this->resource);
+ $n = null;
+ $ret = @socket_select($r, $n, $n, $sec === null ? null : (int) $sec, $usec);
+ if ($ret === false) {
+ throw Exception::createFromGlobalSocketOperation('Failed to select socket for reading');
+ }
+ return !!$ret;
+ }
+
+ /**
+ * check socket to see if a write/send/sendTo will not block
+ *
+ * @param float|null $sec maximum time to wait (in seconds), 0 = immediate polling, null = no limit
+ * @return boolean true = socket ready (write will not block), false = timeout expired, socket is not ready
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_select()
+ */
+ public function selectWrite($sec = 0)
+ {
+ $usec = $sec === null ? 0 : (int) (($sec - floor($sec)) * 1000000);
+ $w = array($this->resource);
+ $n = null;
+ $ret = @socket_select($n, $w, $n, $sec === null ? null : (int) $sec, $usec);
+ if ($ret === false) {
+ throw Exception::createFromGlobalSocketOperation('Failed to select socket for writing');
+ }
+ return !!$ret;
+ }
+
+ /**
+ * send given $buffer to connect()ed / accept()ed socket
+ *
+ * @param string $buffer
+ * @param int $flags
+ * @return int number of bytes actually written (make sure to check against given buffer length!)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::write() if you do not need to pass $flags
+ * @see self::sendTo() if your socket is not connect()ed
+ * @uses socket_send()
+ */
+ public function send($buffer, $flags)
+ {
+ $ret = @socket_send($this->resource, $buffer, strlen($buffer), $flags);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $ret;
+ }
+
+ /**
+ * send given $buffer to socket
+ *
+ * @param string $buffer
+ * @param int $flags
+ * @param string $remote remote/peer address/path
+ * @return int number of bytes actually written
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::send() if your socket is connect()ed
+ * @uses socket_sendto()
+ */
+ public function sendTo($buffer, $flags, $remote)
+ {
+ $ret = @socket_sendto($this->resource, $buffer, strlen($buffer), $flags, $this->unformatAddress($remote, $port), $port);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $ret;
+ }
+
+ /**
+ * enable/disable blocking/nonblocking mode (O_NONBLOCK flag)
+ *
+ * @param boolean $toggle
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @uses socket_set_block()
+ * @uses socket_set_nonblock()
+ */
+ public function setBlocking($toggle = true)
+ {
+ $ret = $toggle ? @socket_set_block($this->resource) : @socket_set_nonblock($this->resource);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * set socket option
+ *
+ * @param int $level
+ * @param int $optname
+ * @param mixed $optval
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::getOption()
+ * @uses socket_set_option()
+ */
+ public function setOption($level, $optname, $optval)
+ {
+ $ret = @socket_set_option($this->resource, $level, $optname, $optval);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * shuts down socket for receiving, sending or both
+ *
+ * @param int $how 0 = shutdown reading, 1 = shutdown writing, 2 = shutdown reading and writing
+ * @return self $this (chainable)
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::close()
+ * @uses socket_shutdown()
+ */
+ public function shutdown($how = 2)
+ {
+ $ret = @socket_shutdown($this->resource, $how);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $this;
+ }
+
+ /**
+ * write $buffer to connect()ed / accept()ed socket
+ *
+ * @param string $buffer
+ * @return int number of bytes actually written
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket or arguments are invalid
+ * @see self::send() if you need to pass flags
+ * @uses socket_write()
+ */
+ public function write($buffer)
+ {
+ $ret = @socket_write($this->resource, $buffer);
+ if ($ret === false) {
+ throw Exception::createFromSocketResource($this->resource);
+ }
+ return $ret;
+ }
+
+ /**
+ * get socket type as passed to socket_create()
+ *
+ * @return int usually either SOCK_STREAM or SOCK_DGRAM
+ * @throws Exception on error
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @uses self::getOption()
+ */
+ public function getType()
+ {
+ return $this->getOption(SOL_SOCKET, SO_TYPE);
+ }
+
+ /**
+ * assert that this socket is alive and its error code is 0
+ *
+ * This will fetch and reset the current socket error code from the
+ * socket and options and will throw an Exception along with error
+ * message and code if the code is not 0, i.e. if it does indicate
+ * an error situation.
+ *
+ * Calling this method should not be needed in most cases and is
+ * likely to not throw an Exception. Each socket operation like
+ * connect(), send(), etc. will throw a dedicated Exception in case
+ * of an error anyway.
+ *
+ * @return self $this (chainable)
+ * @throws Exception if error code is not 0
+ * @throws \Error PHP 8 only: throws \Error when socket is invalid
+ * @uses self::getOption() to retrieve and clear current error code
+ * @uses self::getErrorMessage() to translate error code to
+ */
+ public function assertAlive()
+ {
+ $code = $this->getOption(SOL_SOCKET, SO_ERROR);
+ if ($code !== 0) {
+ throw Exception::createFromCode($code, 'Socket error');
+ }
+ return $this;
+ }
+
+ /**
+ * format given address/host/path and port
+ *
+ * @param string $address
+ * @param int $port
+ * @return string
+ */
+ protected function formatAddress($address, $port)
+ {
+ if ($port !== 0) {
+ if (strpos($address, ':') !== false) {
+ $address = '[' . $address . ']';
+ }
+ $address .= ':' . $port;
+ }
+ return $address;
+ }
+
+ /**
+ * format given address by splitting it into returned address and port set by reference
+ *
+ * @param string $address
+ * @param int $port
+ * @return string address with port removed
+ */
+ protected function unformatAddress($address, &$port)
+ {
+ // [::1]:2 => ::1 2
+ // test:2 => test 2
+ // ::1 => ::1
+ // test => test
+
+ $colon = strrpos($address, ':');
+
+ // there is a colon and this is the only colon or there's a closing IPv6 bracket right before it
+ if ($colon !== false && (strpos($address, ':') === $colon || strpos($address, ']') === ($colon - 1))) {
+ $port = (int)substr($address, $colon + 1);
+ $address = substr($address, 0, $colon);
+
+ // remove IPv6 square brackets
+ if (substr($address, 0, 1) === '[') {
+ $address = substr($address, 1, -1);
+ }
+ }
+ return $address;
+ }
+}
diff --git a/vendor/clue/socks-react/LICENSE b/vendor/clue/socks-react/LICENSE
new file mode 100644
index 0000000..8efa9aa
--- /dev/null
+++ b/vendor/clue/socks-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2011 Christian Lück
+
+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/clue/socks-react/composer.json b/vendor/clue/socks-react/composer.json
new file mode 100644
index 0000000..c57742b
--- /dev/null
+++ b/vendor/clue/socks-react/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "clue/socks-react",
+ "description": "Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.",
+ "keywords": ["socks client", "socks server", "socks5", "socks4a", "proxy server", "tcp tunnel", "async", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-socks",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "clue/connection-manager-extra": "^1.0 || ^0.7",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\Socks\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Socks\\": "tests/" }
+ }
+}
diff --git a/vendor/clue/socks-react/src/Client.php b/vendor/clue/socks-react/src/Client.php
new file mode 100644
index 0000000..5350b54
--- /dev/null
+++ b/vendor/clue/socks-react/src/Client.php
@@ -0,0 +1,452 @@
+<?php
+
+namespace Clue\React\Socks;
+
+use React\Promise;
+use React\Promise\PromiseInterface;
+use React\Promise\Deferred;
+use React\Socket\ConnectionInterface;
+use React\Socket\Connector;
+use React\Socket\ConnectorInterface;
+use React\Socket\FixedUriConnector;
+use Exception;
+use InvalidArgumentException;
+use RuntimeException;
+
+final class Client implements ConnectorInterface
+{
+ /**
+ * @var ConnectorInterface
+ */
+ private $connector;
+
+ private $socksUri;
+
+ private $protocolVersion = 5;
+
+ private $auth = null;
+
+ /**
+ * @param string $socksUri
+ * @param ?ConnectorInterface $connector
+ * @throws InvalidArgumentException
+ */
+ public function __construct($socksUri, ConnectorInterface $connector = null)
+ {
+ // support `sockss://` scheme for SOCKS over TLS
+ // support `socks+unix://` scheme for Unix domain socket (UDS) paths
+ if (preg_match('/^(socks(?:5|4)?)(s|\+unix):\/\/(.*?@)?(.+?)$/', $socksUri, $match)) {
+ // rewrite URI to parse SOCKS scheme, authentication and dummy host
+ $socksUri = $match[1] . '://' . $match[3] . 'localhost';
+
+ // connector uses appropriate transport scheme and explicit host given
+ $connector = new FixedUriConnector(
+ ($match[2] === 's' ? 'tls://' : 'unix://') . $match[4],
+ $connector ?: new Connector()
+ );
+ }
+
+ // assume default scheme if none is given
+ if (strpos($socksUri, '://') === false) {
+ $socksUri = 'socks://' . $socksUri;
+ }
+
+ // parse URI into individual parts
+ $parts = parse_url($socksUri);
+ if (!$parts || !isset($parts['scheme'], $parts['host'])) {
+ throw new InvalidArgumentException('Invalid SOCKS server URI "' . $socksUri . '"');
+ }
+
+ // assume default port
+ if (!isset($parts['port'])) {
+ $parts['port'] = 1080;
+ }
+
+ // user or password in URI => SOCKS5 authentication
+ if (isset($parts['user']) || isset($parts['pass'])) {
+ if ($parts['scheme'] !== 'socks' && $parts['scheme'] !== 'socks5') {
+ // fail if any other protocol version given explicitly
+ throw new InvalidArgumentException('Authentication requires SOCKS5. Consider using protocol version 5 or waive authentication');
+ }
+ $parts += array('user' => '', 'pass' => '');
+ $this->setAuth(rawurldecode($parts['user']), rawurldecode($parts['pass']));
+ }
+
+ // check for valid protocol version from URI scheme
+ $this->setProtocolVersionFromScheme($parts['scheme']);
+
+ $this->socksUri = $parts['host'] . ':' . $parts['port'];
+ $this->connector = $connector ?: new Connector();
+ }
+
+ private function setProtocolVersionFromScheme($scheme)
+ {
+ if ($scheme === 'socks' || $scheme === 'socks5') {
+ $this->protocolVersion = 5;
+ } elseif ($scheme === 'socks4') {
+ $this->protocolVersion = 4;
+ } else {
+ throw new InvalidArgumentException('Invalid protocol version given "' . $scheme . '://"');
+ }
+ }
+
+ /**
+ * set login data for username/password authentication method (RFC1929)
+ *
+ * @param string $username
+ * @param string $password
+ * @link http://tools.ietf.org/html/rfc1929
+ */
+ private function setAuth($username, $password)
+ {
+ if (strlen($username) > 255 || strlen($password) > 255) {
+ throw new InvalidArgumentException('Both username and password MUST NOT exceed a length of 255 bytes each');
+ }
+ $this->auth = pack('C2', 0x01, strlen($username)) . $username . pack('C', strlen($password)) . $password;
+ }
+
+ /**
+ * Establish a TCP/IP connection to the given target URI through the SOCKS server
+ *
+ * Many higher-level networking protocols build on top of TCP. It you're dealing
+ * with one such client implementation, it probably uses/accepts an instance
+ * implementing ReactPHP's `ConnectorInterface` (and usually its default `Connector`
+ * instance). In this case you can also pass this `Connector` instance instead
+ * to make this client implementation SOCKS-aware. That's it.
+ *
+ * @param string $uri
+ * @return PromiseInterface Promise<ConnectionInterface,Exception>
+ */
+ public function connect($uri)
+ {
+ if (strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ }
+
+ $parts = parse_url($uri);
+ if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
+ return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
+ }
+
+ $host = trim($parts['host'], '[]');
+ $port = $parts['port'];
+
+ if (strlen($host) > 255 || $port > 65535 || $port < 0 || (string)$port !== (string)(int)$port) {
+ return Promise\reject(new InvalidArgumentException('Invalid target specified'));
+ }
+
+ // construct URI to SOCKS server to connect to
+ $socksUri = $this->socksUri;
+
+ // append path from URI if given
+ if (isset($parts['path'])) {
+ $socksUri .= $parts['path'];
+ }
+
+ // parse query args
+ $args = array();
+ if (isset($parts['query'])) {
+ parse_str($parts['query'], $args);
+ }
+
+ // append hostname from URI to query string unless explicitly given
+ if (!isset($args['hostname'])) {
+ $args['hostname'] = $host;
+ }
+
+ // append query string
+ $socksUri .= '?' . http_build_query($args, '', '&');
+
+ // append fragment from URI if given
+ if (isset($parts['fragment'])) {
+ $socksUri .= '#' . $parts['fragment'];
+ }
+
+ // start TCP/IP connection to SOCKS server
+ $connecting = $this->connector->connect($socksUri);
+
+ $deferred = new Deferred(function ($_, $reject) use ($uri, $connecting) {
+ $reject(new RuntimeException(
+ 'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
+ defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
+ ));
+
+ // either close active connection or cancel pending connection attempt
+ $connecting->then(function (ConnectionInterface $stream) {
+ $stream->close();
+ });
+ $connecting->cancel();
+ });
+
+ // handle SOCKS protocol once connection is ready
+ // resolve plain connection once SOCKS protocol is completed
+ $that = $this;
+ $connecting->then(
+ function (ConnectionInterface $stream) use ($that, $host, $port, $deferred, $uri) {
+ $that->handleConnectedSocks($stream, $host, $port, $deferred, $uri);
+ },
+ function (Exception $e) use ($uri, $deferred) {
+ $deferred->reject($e = new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
+ $e
+ ));
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as &$one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as &$arg) {
+ if ($arg instanceof \Closure) {
+ $arg = 'Object(' . \get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ }
+ );
+
+ return $deferred->promise();
+ }
+
+ /**
+ * Internal helper used to handle the communication with the SOCKS server
+ *
+ * @param ConnectionInterface $stream
+ * @param string $host
+ * @param int $port
+ * @param Deferred $deferred
+ * @param string $uri
+ * @return void
+ * @internal
+ */
+ public function handleConnectedSocks(ConnectionInterface $stream, $host, $port, Deferred $deferred, $uri)
+ {
+ $reader = new StreamReader();
+ $stream->on('data', array($reader, 'write'));
+
+ $stream->on('error', $onError = function (Exception $e) use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy caused a stream error (EIO)',
+ defined('SOCKET_EIO') ? SOCKET_EIO : 5, $e)
+ );
+ });
+
+ $stream->on('close', $onClose = function () use ($deferred, $uri) {
+ $deferred->reject(new RuntimeException(
+ 'Connection to ' . $uri . ' failed because connection to proxy was lost while waiting for response from proxy (ECONNRESET)',
+ defined('SOCKET_ECONNRESET') ? SOCKET_ECONNRESET : 104)
+ );
+ });
+
+ if ($this->protocolVersion === 5) {
+ $promise = $this->handleSocks5($stream, $host, $port, $reader, $uri);
+ } else {
+ $promise = $this->handleSocks4($stream, $host, $port, $reader, $uri);
+ }
+
+ $promise->then(function () use ($deferred, $stream, $reader, $onError, $onClose) {
+ $stream->removeListener('data', array($reader, 'write'));
+ $stream->removeListener('error', $onError);
+ $stream->removeListener('close', $onClose);
+
+ $deferred->resolve($stream);
+ }, function (Exception $error) use ($deferred, $stream, $uri) {
+ // pass custom RuntimeException through as-is, otherwise wrap in protocol error
+ if (!$error instanceof RuntimeException) {
+ $error = new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy returned invalid response (EBADMSG)',
+ defined('SOCKET_EBADMSG') ? SOCKET_EBADMSG: 71,
+ $error
+ );
+ }
+
+ $deferred->reject($error);
+ $stream->close();
+ });
+ }
+
+ private function handleSocks4(ConnectionInterface $stream, $host, $port, StreamReader $reader, $uri)
+ {
+ // do not resolve hostname. only try to convert to IP
+ $ip = ip2long($host);
+
+ // send IP or (0.0.0.1) if invalid
+ $data = pack('C2nNC', 0x04, 0x01, $port, $ip === false ? 1 : $ip, 0x00);
+
+ if ($ip === false) {
+ // host is not a valid IP => send along hostname (SOCKS4a)
+ $data .= $host . pack('C', 0x00);
+ }
+
+ $stream->write($data);
+
+ return $reader->readBinary(array(
+ 'null' => 'C',
+ 'status' => 'C',
+ 'port' => 'n',
+ 'ip' => 'N'
+ ))->then(function ($data) use ($uri) {
+ if ($data['null'] !== 0x00) {
+ throw new Exception('Invalid SOCKS response');
+ }
+ if ($data['status'] !== 0x5a) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy refused connection with error code ' . sprintf('0x%02X', $data['status']) . ' (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ );
+ }
+ });
+ }
+
+ private function handleSocks5(ConnectionInterface $stream, $host, $port, StreamReader $reader, $uri)
+ {
+ // protocol version 5
+ $data = pack('C', 0x05);
+
+ $auth = $this->auth;
+ if ($auth === null) {
+ // one method, no authentication
+ $data .= pack('C2', 0x01, 0x00);
+ } else {
+ // two methods, username/password and no authentication
+ $data .= pack('C3', 0x02, 0x02, 0x00);
+ }
+ $stream->write($data);
+
+ $that = $this;
+
+ return $reader->readBinary(array(
+ 'version' => 'C',
+ 'method' => 'C'
+ ))->then(function ($data) use ($auth, $stream, $reader, $uri) {
+ if ($data['version'] !== 0x05) {
+ throw new Exception('Version/Protocol mismatch');
+ }
+
+ if ($data['method'] === 0x02 && $auth !== null) {
+ // username/password authentication requested and provided
+ $stream->write($auth);
+
+ return $reader->readBinary(array(
+ 'version' => 'C',
+ 'status' => 'C'
+ ))->then(function ($data) use ($uri) {
+ if ($data['version'] !== 0x01 || $data['status'] !== 0x00) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy denied access with given authentication details (EACCES)',
+ defined('SOCKET_EACCES') ? SOCKET_EACCES : 13
+ );
+ }
+ });
+ } else if ($data['method'] !== 0x00) {
+ // any other method than "no authentication"
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy denied access due to unsupported authentication method (EACCES)',
+ defined('SOCKET_EACCES') ? SOCKET_EACCES : 13
+ );
+ }
+ })->then(function () use ($stream, $reader, $host, $port) {
+ // do not resolve hostname. only try to convert to (binary/packed) IP
+ $ip = @inet_pton($host);
+
+ $data = pack('C3', 0x05, 0x01, 0x00);
+ if ($ip === false) {
+ // not an IP, send as hostname
+ $data .= pack('C2', 0x03, strlen($host)) . $host;
+ } else {
+ // send as IPv4 / IPv6
+ $data .= pack('C', (strpos($host, ':') === false) ? 0x01 : 0x04) . $ip;
+ }
+ $data .= pack('n', $port);
+
+ $stream->write($data);
+
+ return $reader->readBinary(array(
+ 'version' => 'C',
+ 'status' => 'C',
+ 'null' => 'C',
+ 'type' => 'C'
+ ));
+ })->then(function ($data) use ($reader, $uri) {
+ if ($data['version'] !== 0x05 || $data['null'] !== 0x00) {
+ throw new Exception('Invalid SOCKS response');
+ }
+ if ($data['status'] !== 0x00) {
+ // map limited list of SOCKS error codes to common socket error conditions
+ // @link https://tools.ietf.org/html/rfc1928#section-6
+ if ($data['status'] === Server::ERROR_GENERAL) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy refused connection with general server failure (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ );
+ } elseif ($data['status'] === Server::ERROR_NOT_ALLOWED_BY_RULESET) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy denied access due to ruleset (EACCES)',
+ defined('SOCKET_EACCES') ? SOCKET_EACCES : 13
+ );
+ } elseif ($data['status'] === Server::ERROR_NETWORK_UNREACHABLE) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy reported network unreachable (ENETUNREACH)',
+ defined('SOCKET_ENETUNREACH') ? SOCKET_ENETUNREACH : 101
+ );
+ } elseif ($data['status'] === Server::ERROR_HOST_UNREACHABLE) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy reported host unreachable (EHOSTUNREACH)',
+ defined('SOCKET_EHOSTUNREACH') ? SOCKET_EHOSTUNREACH : 113
+ );
+ } elseif ($data['status'] === Server::ERROR_CONNECTION_REFUSED) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy reported connection refused (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ );
+ } elseif ($data['status'] === Server::ERROR_TTL) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy reported TTL/timeout expired (ETIMEDOUT)',
+ defined('SOCKET_ETIMEDOUT') ? SOCKET_ETIMEDOUT : 110
+ );
+ } elseif ($data['status'] === Server::ERROR_COMMAND_UNSUPPORTED) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy does not support the CONNECT command (EPROTO)',
+ defined('SOCKET_EPROTO') ? SOCKET_EPROTO : 71
+ );
+ } elseif ($data['status'] === Server::ERROR_ADDRESS_UNSUPPORTED) {
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy does not support this address type (EPROTO)',
+ defined('SOCKET_EPROTO') ? SOCKET_EPROTO : 71
+ );
+ }
+
+ throw new RuntimeException(
+ 'Connection to ' . $uri . ' failed because proxy server refused connection with unknown error code ' . sprintf('0x%02X', $data['status']) . ' (ECONNREFUSED)',
+ defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
+ );
+ }
+ if ($data['type'] === 0x01) {
+ // IPv4 address => skip IP and port
+ return $reader->readLength(6);
+ } elseif ($data['type'] === 0x03) {
+ // domain name => read domain name length
+ return $reader->readBinary(array(
+ 'length' => 'C'
+ ))->then(function ($data) use ($reader) {
+ // skip domain name and port
+ return $reader->readLength($data['length'] + 2);
+ });
+ } elseif ($data['type'] === 0x04) {
+ // IPv6 address => skip IP and port
+ return $reader->readLength(18);
+ } else {
+ throw new Exception('Invalid SOCKS reponse: Invalid address type');
+ }
+ });
+ }
+}
diff --git a/vendor/clue/socks-react/src/Server.php b/vendor/clue/socks-react/src/Server.php
new file mode 100644
index 0000000..2405f3e
--- /dev/null
+++ b/vendor/clue/socks-react/src/Server.php
@@ -0,0 +1,399 @@
+<?php
+
+namespace Clue\React\Socks;
+
+use React\Socket\ServerInterface;
+use React\Promise\PromiseInterface;
+use React\Socket\ConnectorInterface;
+use React\Socket\Connector;
+use React\Socket\ConnectionInterface;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use \UnexpectedValueException;
+use \InvalidArgumentException;
+use \Exception;
+use React\Promise\Timer\TimeoutException;
+
+final class Server
+{
+ // the following error codes are only used for SOCKS5 only
+ /** @internal */
+ const ERROR_GENERAL = 0x01;
+ /** @internal */
+ const ERROR_NOT_ALLOWED_BY_RULESET = 0x02;
+ /** @internal */
+ const ERROR_NETWORK_UNREACHABLE = 0x03;
+ /** @internal */
+ const ERROR_HOST_UNREACHABLE = 0x04;
+ /** @internal */
+ const ERROR_CONNECTION_REFUSED = 0x05;
+ /** @internal */
+ const ERROR_TTL = 0x06;
+ /** @internal */
+ const ERROR_COMMAND_UNSUPPORTED = 0x07;
+ /** @internal */
+ const ERROR_ADDRESS_UNSUPPORTED = 0x08;
+
+ /** @var LoopInterface */
+ private $loop;
+
+ /** @var ConnectorInterface */
+ private $connector;
+
+ /**
+ * @var null|callable
+ */
+ private $auth;
+
+ /**
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param ?LoopInterface $loop
+ * @param ?ConnectorInterface $connector
+ * @param null|array|callable $auth
+ */
+ public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null, $auth = null)
+ {
+ if (\is_array($auth)) {
+ // wrap authentication array in authentication callback
+ $this->auth = function ($username, $password) use ($auth) {
+ return \React\Promise\resolve(
+ isset($auth[$username]) && (string)$auth[$username] === $password
+ );
+ };
+ } elseif (\is_callable($auth)) {
+ // wrap authentication callback in order to cast its return value to a promise
+ $this->auth = function($username, $password, $remote) use ($auth) {
+ return \React\Promise\resolve(
+ \call_user_func($auth, $username, $password, $remote)
+ );
+ };
+ } elseif ($auth !== null) {
+ throw new \InvalidArgumentException('Invalid authenticator given');
+ }
+
+ $this->loop = $loop ?: Loop::get();
+ $this->connector = $connector ?: new Connector(array(), $this->loop);
+ }
+
+ /**
+ * @param ServerInterface $socket
+ * @return void
+ */
+ public function listen(ServerInterface $socket)
+ {
+ $that = $this;
+ $socket->on('connection', function ($connection) use ($that) {
+ $that->onConnection($connection);
+ });
+ }
+
+ /** @internal */
+ public function onConnection(ConnectionInterface $connection)
+ {
+ $that = $this;
+ $handling = $this->handleSocks($connection)->then(null, function () use ($connection, $that) {
+ // SOCKS failed => close connection
+ $that->endConnection($connection);
+ });
+
+ $connection->on('close', function () use ($handling) {
+ $handling->cancel();
+ });
+ }
+
+ /**
+ * [internal] gracefully shutdown connection by flushing all remaining data and closing stream
+ *
+ * @internal
+ */
+ public function endConnection(ConnectionInterface $stream)
+ {
+ $tid = true;
+ $loop = $this->loop;
+
+ // cancel below timer in case connection is closed in time
+ $stream->once('close', function () use (&$tid, $loop) {
+ // close event called before the timer was set up, so everything is okay
+ if ($tid === true) {
+ // make sure to not start a useless timer
+ $tid = false;
+ } else {
+ $loop->cancelTimer($tid);
+ }
+ });
+
+ // shut down connection by pausing input data, flushing outgoing buffer and then exit
+ $stream->pause();
+ $stream->end();
+
+ // check if connection is not already closed
+ if ($tid === true) {
+ // fall back to forcefully close connection in 3 seconds if buffer can not be flushed
+ $tid = $loop->addTimer(3.0, array($stream,'close'));
+ }
+ }
+
+ private function handleSocks(ConnectionInterface $stream)
+ {
+ $reader = new StreamReader();
+ $stream->on('data', array($reader, 'write'));
+
+ $that = $this;
+ $auth = $this->auth;
+
+ return $reader->readByte()->then(function ($version) use ($stream, $that, $auth, $reader){
+ if ($version === 0x04) {
+ if ($auth !== null) {
+ throw new UnexpectedValueException('SOCKS4 not allowed because authentication is required');
+ }
+ return $that->handleSocks4($stream, $reader);
+ } else if ($version === 0x05) {
+ return $that->handleSocks5($stream, $auth, $reader);
+ }
+ throw new UnexpectedValueException('Unexpected/unknown version number');
+ });
+ }
+
+ /** @internal */
+ public function handleSocks4(ConnectionInterface $stream, StreamReader $reader)
+ {
+ $remote = $stream->getRemoteAddress();
+ if ($remote !== null) {
+ // remove transport scheme and prefix socks4:// instead
+ $secure = strpos($remote, 'tls://') === 0;
+ if (($pos = strpos($remote, '://')) !== false) {
+ $remote = substr($remote, $pos + 3);
+ }
+ $remote = 'socks4' . ($secure ? 's' : '') . '://' . $remote;
+ }
+
+ $that = $this;
+ return $reader->readByteAssert(0x01)->then(function () use ($reader) {
+ return $reader->readBinary(array(
+ 'port' => 'n',
+ 'ipLong' => 'N',
+ 'null' => 'C'
+ ));
+ })->then(function ($data) use ($reader, $remote) {
+ if ($data['null'] !== 0x00) {
+ throw new Exception('Not a null byte');
+ }
+ if ($data['ipLong'] === 0) {
+ throw new Exception('Invalid IP');
+ }
+ if ($data['port'] === 0) {
+ throw new Exception('Invalid port');
+ }
+ if ($data['ipLong'] < 256) {
+ // invalid IP => probably a SOCKS4a request which appends the hostname
+ return $reader->readStringNull()->then(function ($string) use ($data, $remote){
+ return array($string, $data['port'], $remote);
+ });
+ } else {
+ $ip = long2ip($data['ipLong']);
+ return array($ip, $data['port'], $remote);
+ }
+ })->then(function ($target) use ($stream, $that) {
+ return $that->connectTarget($stream, $target)->then(function (ConnectionInterface $remote) use ($stream){
+ $stream->write(pack('C8', 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+
+ return $remote;
+ }, function($error) use ($stream){
+ $stream->end(pack('C8', 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+
+ throw $error;
+ });
+ }, function($error) {
+ throw new UnexpectedValueException('SOCKS4 protocol error',0,$error);
+ });
+ }
+
+ /** @internal */
+ public function handleSocks5(ConnectionInterface $stream, $auth, StreamReader $reader)
+ {
+ $remote = $stream->getRemoteAddress();
+ if ($remote !== null) {
+ // remove transport scheme and prefix socks5:// instead
+ $secure = strpos($remote, 'tls://') === 0;
+ if (($pos = strpos($remote, '://')) !== false) {
+ $remote = substr($remote, $pos + 3);
+ }
+ $remote = 'socks' . ($secure ? 's' : '') . '://' . $remote;
+ }
+
+ $that = $this;
+ return $reader->readByte()->then(function ($num) use ($reader) {
+ // $num different authentication mechanisms offered
+ return $reader->readLength($num);
+ })->then(function ($methods) use ($reader, $stream, $auth, &$remote) {
+ if ($auth === null && strpos($methods,"\x00") !== false) {
+ // accept "no authentication"
+ $stream->write(pack('C2', 0x05, 0x00));
+
+ return 0x00;
+ } else if ($auth !== null && strpos($methods,"\x02") !== false) {
+ // username/password authentication (RFC 1929) sub negotiation
+ $stream->write(pack('C2', 0x05, 0x02));
+ return $reader->readByteAssert(0x01)->then(function () use ($reader) {
+ return $reader->readByte();
+ })->then(function ($length) use ($reader) {
+ return $reader->readLength($length);
+ })->then(function ($username) use ($reader, $auth, $stream, &$remote) {
+ return $reader->readByte()->then(function ($length) use ($reader) {
+ return $reader->readLength($length);
+ })->then(function ($password) use ($username, $auth, $stream, &$remote) {
+ // username and password given => authenticate
+
+ // prefix username/password to remote URI
+ if ($remote !== null) {
+ $remote = str_replace('://', '://' . rawurlencode($username) . ':' . rawurlencode($password) . '@', $remote);
+ }
+
+ return $auth($username, $password, $remote)->then(function ($authenticated) use ($stream) {
+ if ($authenticated) {
+ // accept auth
+ $stream->write(pack('C2', 0x01, 0x00));
+ } else {
+ // reject auth => send any code but 0x00
+ $stream->end(pack('C2', 0x01, 0xFF));
+ throw new UnexpectedValueException('Authentication denied');
+ }
+ }, function ($e) use ($stream) {
+ // reject failed authentication => send any code but 0x00
+ $stream->end(pack('C2', 0x01, 0xFF));
+ throw new UnexpectedValueException('Authentication error', 0, $e);
+ });
+ });
+ });
+ } else {
+ // reject all offered authentication methods
+ $stream->write(pack('C2', 0x05, 0xFF));
+ throw new UnexpectedValueException('No acceptable authentication mechanism found');
+ }
+ })->then(function ($method) use ($reader) {
+ return $reader->readBinary(array(
+ 'version' => 'C',
+ 'command' => 'C',
+ 'null' => 'C',
+ 'type' => 'C'
+ ));
+ })->then(function ($data) use ($reader) {
+ if ($data['version'] !== 0x05) {
+ throw new UnexpectedValueException('Invalid SOCKS version');
+ }
+ if ($data['command'] !== 0x01) {
+ throw new UnexpectedValueException('Only CONNECT requests supported', Server::ERROR_COMMAND_UNSUPPORTED);
+ }
+// if ($data['null'] !== 0x00) {
+// throw new UnexpectedValueException('Reserved byte has to be NULL');
+// }
+ if ($data['type'] === 0x03) {
+ // target hostname string
+ return $reader->readByte()->then(function ($len) use ($reader) {
+ return $reader->readLength($len);
+ });
+ } else if ($data['type'] === 0x01) {
+ // target IPv4
+ return $reader->readLength(4)->then(function ($addr) {
+ return inet_ntop($addr);
+ });
+ } else if ($data['type'] === 0x04) {
+ // target IPv6
+ return $reader->readLength(16)->then(function ($addr) {
+ return inet_ntop($addr);
+ });
+ } else {
+ throw new UnexpectedValueException('Invalid address type', Server::ERROR_ADDRESS_UNSUPPORTED);
+ }
+ })->then(function ($host) use ($reader, &$remote) {
+ return $reader->readBinary(array('port'=>'n'))->then(function ($data) use ($host, &$remote) {
+ return array($host, $data['port'], $remote);
+ });
+ })->then(function ($target) use ($that, $stream) {
+ return $that->connectTarget($stream, $target);
+ }, function($error) use ($stream) {
+ throw new UnexpectedValueException('SOCKS5 protocol error', $error->getCode(), $error);
+ })->then(function (ConnectionInterface $remote) use ($stream) {
+ $stream->write(pack('C4Nn', 0x05, 0x00, 0x00, 0x01, 0, 0));
+
+ return $remote;
+ }, function(Exception $error) use ($stream){
+ $stream->write(pack('C4Nn', 0x05, $error->getCode() === 0 ? Server::ERROR_GENERAL : $error->getCode(), 0x00, 0x01, 0, 0));
+
+ throw $error;
+ });
+ }
+
+ /** @internal */
+ public function connectTarget(ConnectionInterface $stream, array $target)
+ {
+ $uri = $target[0];
+ if (strpos($uri, ':') !== false) {
+ $uri = '[' . $uri . ']';
+ }
+ $uri .= ':' . $target[1];
+
+ // validate URI so a string hostname can not pass excessive URI parts
+ $parts = parse_url('tcp://' . $uri);
+ if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || count($parts) !== 3) {
+ return \React\Promise\reject(new InvalidArgumentException('Invalid target URI given'));
+ }
+
+ if (isset($target[2])) {
+ $uri .= '?source=' . rawurlencode($target[2]);
+ }
+
+ $that = $this;
+ $connecting = $this->connector->connect($uri);
+
+ $stream->on('close', function () use ($connecting) {
+ $connecting->cancel();
+ });
+
+ return $connecting->then(function (ConnectionInterface $remote) use ($stream, $that) {
+ $stream->pipe($remote, array('end'=>false));
+ $remote->pipe($stream, array('end'=>false));
+
+ // remote end closes connection => stop reading from local end, try to flush buffer to local and disconnect local
+ $remote->on('end', function() use ($stream, $that) {
+ $that->endConnection($stream);
+ });
+
+ // local end closes connection => stop reading from remote end, try to flush buffer to remote and disconnect remote
+ $stream->on('end', function() use ($remote, $that) {
+ $that->endConnection($remote);
+ });
+
+ // set bigger buffer size of 100k to improve performance
+ $stream->bufferSize = $remote->bufferSize = 100 * 1024 * 1024;
+
+ return $remote;
+ }, function(Exception $error) {
+ // default to general/unknown error
+ $code = Server::ERROR_GENERAL;
+
+ // map common socket error conditions to limited list of SOCKS error codes
+ if ((defined('SOCKET_EACCES') && $error->getCode() === SOCKET_EACCES) || $error->getCode() === 13) {
+ $code = Server::ERROR_NOT_ALLOWED_BY_RULESET;
+ } elseif ((defined('SOCKET_EHOSTUNREACH') && $error->getCode() === SOCKET_EHOSTUNREACH) || $error->getCode() === 113) {
+ $code = Server::ERROR_HOST_UNREACHABLE;
+ } elseif ((defined('SOCKET_ENETUNREACH') && $error->getCode() === SOCKET_ENETUNREACH) || $error->getCode() === 101) {
+ $code = Server::ERROR_NETWORK_UNREACHABLE;
+ } elseif ((defined('SOCKET_ECONNREFUSED') && $error->getCode() === SOCKET_ECONNREFUSED) || $error->getCode() === 111 || $error->getMessage() === 'Connection refused') {
+ // Socket component does not currently assign an error code for this, so we have to resort to checking the exception message
+ $code = Server::ERROR_CONNECTION_REFUSED;
+ } elseif ((defined('SOCKET_ETIMEDOUT') && $error->getCode() === SOCKET_ETIMEDOUT) || $error->getCode() === 110 || $error instanceof TimeoutException) {
+ // Socket component does not currently assign an error code for this, but we can rely on the TimeoutException
+ $code = Server::ERROR_TTL;
+ }
+
+ throw new UnexpectedValueException('Unable to connect to remote target', $code, $error);
+ });
+ }
+}
diff --git a/vendor/clue/socks-react/src/StreamReader.php b/vendor/clue/socks-react/src/StreamReader.php
new file mode 100644
index 0000000..f01d252
--- /dev/null
+++ b/vendor/clue/socks-react/src/StreamReader.php
@@ -0,0 +1,149 @@
+<?php
+
+namespace Clue\React\Socks;
+
+use React\Promise\Deferred;
+use \InvalidArgumentException;
+use \UnexpectedValueException;
+
+/**
+ * @internal
+ */
+final class StreamReader
+{
+ const RET_DONE = true;
+ const RET_INCOMPLETE = null;
+
+ private $buffer = '';
+ private $queue = array();
+
+ public function write($data)
+ {
+ $this->buffer .= $data;
+
+ do {
+ $current = reset($this->queue);
+
+ if ($current === false) {
+ break;
+ }
+
+ /* @var $current Closure */
+
+ $ret = $current($this->buffer);
+
+ if ($ret === self::RET_INCOMPLETE) {
+ // current is incomplete, so wait for further data to arrive
+ break;
+ } else {
+ // current is done, remove from list and continue with next
+ array_shift($this->queue);
+ }
+ } while (true);
+ }
+
+ public function readBinary($structure)
+ {
+ $length = 0;
+ $unpack = '';
+ foreach ($structure as $name=>$format) {
+ if ($length !== 0) {
+ $unpack .= '/';
+ }
+ $unpack .= $format . $name;
+
+ if ($format === 'C') {
+ ++$length;
+ } else if ($format === 'n') {
+ $length += 2;
+ } else if ($format === 'N') {
+ $length += 4;
+ } else {
+ throw new InvalidArgumentException('Invalid format given');
+ }
+ }
+
+ return $this->readLength($length)->then(function ($response) use ($unpack) {
+ return unpack($unpack, $response);
+ });
+ }
+
+ public function readLength($bytes)
+ {
+ $deferred = new Deferred();
+
+ $this->readBufferCallback(function (&$buffer) use ($bytes, $deferred) {
+ if (strlen($buffer) >= $bytes) {
+ $deferred->resolve((string)substr($buffer, 0, $bytes));
+ $buffer = (string)substr($buffer, $bytes);
+
+ return StreamReader::RET_DONE;
+ }
+ });
+
+ return $deferred->promise();
+ }
+
+ public function readByte()
+ {
+ return $this->readBinary(array(
+ 'byte' => 'C'
+ ))->then(function ($data) {
+ return $data['byte'];
+ });
+ }
+
+ public function readByteAssert($expect)
+ {
+ return $this->readByte()->then(function ($byte) use ($expect) {
+ if ($byte !== $expect) {
+ throw new UnexpectedValueException('Unexpected byte encountered');
+ }
+ return $byte;
+ });
+ }
+
+ public function readStringNull()
+ {
+ $deferred = new Deferred();
+ $string = '';
+
+ $that = $this;
+ $readOne = function () use (&$readOne, $that, $deferred, &$string) {
+ $that->readByte()->then(function ($byte) use ($deferred, &$string, $readOne) {
+ if ($byte === 0x00) {
+ $deferred->resolve($string);
+ } else {
+ $string .= chr($byte);
+ $readOne();
+ }
+ });
+ };
+ $readOne();
+
+ return $deferred->promise();
+ }
+
+ public function readBufferCallback(/* callable */ $callable)
+ {
+ if (!is_callable($callable)) {
+ throw new InvalidArgumentException('Given function must be callable');
+ }
+
+ if ($this->queue) {
+ $this->queue []= $callable;
+ } else {
+ $this->queue = array($callable);
+
+ if ($this->buffer !== '') {
+ // this is the first element in the queue and the buffer is filled => trigger write procedure
+ $this->write('');
+ }
+ }
+ }
+
+ public function getBuffer()
+ {
+ return $this->buffer;
+ }
+}
diff --git a/vendor/clue/stdio-react/LICENSE b/vendor/clue/stdio-react/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/stdio-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+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/clue/stdio-react/composer.json b/vendor/clue/stdio-react/composer.json
new file mode 100644
index 0000000..0e86dcb
--- /dev/null
+++ b/vendor/clue/stdio-react/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "clue/stdio-react",
+ "description": "Async, event-driven console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP",
+ "keywords": ["stdio", "stdin", "stdout", "interactive", "CLI", "readline", "autocomplete", "autocompletion", "history", "ReactPHP", "async"],
+ "homepage": "https://github.com/clue/reactphp-stdio",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "clue/term-react": "^1.0 || ^0.1.1",
+ "clue/utf8-react": "^1.0 || ^0.1",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/arguments": "^2.0",
+ "clue/commander": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\Stdio\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Stdio\\": "tests/" }
+ }
+}
diff --git a/vendor/clue/stdio-react/src/Readline.php b/vendor/clue/stdio-react/src/Readline.php
new file mode 100644
index 0000000..b75650e
--- /dev/null
+++ b/vendor/clue/stdio-react/src/Readline.php
@@ -0,0 +1,1017 @@
+<?php
+
+namespace Clue\React\Stdio;
+
+use Clue\React\Term\ControlCodeParser;
+use Clue\React\Utf8\Sequencer as Utf8Sequencer;
+use Evenement\EventEmitter;
+use Evenement\EventEmitterInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @deprecated 2.3.0 Use `Stdio` instead
+ * @see Stdio
+ */
+class Readline extends EventEmitter implements ReadableStreamInterface
+{
+ private $prompt = '';
+ private $linebuffer = '';
+ private $linepos = 0;
+ private $echo = true;
+ private $move = true;
+ private $bell = true;
+ private $encoding = 'utf-8';
+
+ private $input;
+ private $output;
+ private $sequencer;
+ private $closed = false;
+
+ private $historyLines = array();
+ private $historyPosition = null;
+ private $historyUnsaved = null;
+ private $historyLimit = 500;
+
+ private $autocomplete = null;
+ private $autocompleteSuggestions = 8;
+
+ public function __construct(ReadableStreamInterface $input, WritableStreamInterface $output, EventEmitterInterface $base = null)
+ {
+ $this->input = $input;
+ $this->output = $output;
+
+ if (!$this->input->isReadable()) {
+ $this->close();
+ return;
+ }
+ // push input through control code parser
+ $parser = new ControlCodeParser($input);
+
+ $that = $this;
+ $codes = array(
+ "\n" => 'onKeyEnter', // ^J
+ "\x7f" => 'onKeyBackspace', // ^?
+ "\t" => 'onKeyTab', // ^I
+ "\x04" => 'handleEnd', // ^D
+
+ "\033[A" => 'onKeyUp',
+ "\033[B" => 'onKeyDown',
+ "\033[C" => 'onKeyRight',
+ "\033[D" => 'onKeyLeft',
+
+ "\033[1~" => 'onKeyHome',
+// "\033[2~" => 'onKeyInsert',
+ "\033[3~" => 'onKeyDelete',
+ "\033[4~" => 'onKeyEnd',
+
+// "\033[20~" => 'onKeyF10',
+ );
+ $decode = function ($code) use ($codes, $that, $base) {
+ // The user confirms input with enter key which should usually
+ // generate a NL (`\n`) character. Common terminals also seem to
+ // accept a CR (`\r`) character in place and handle this just like a
+ // NL. Similarly `ext-readline` uses different `icrnl` and `igncr`
+ // TTY settings on some platforms, so we also accept CR as an alias
+ // for NL here. This implies key binding for NL will also trigger.
+ if ($code === "\r") {
+ $code = "\n";
+ }
+
+ // forward compatibility: check if any key binding exists on base Stdio instance
+ if ($base !== null && $base->listeners($code)) {
+ $base->emit($code, array($code));
+ return;
+ }
+
+ // deprecated: check if any key binding exists on this Readline instance
+ if ($that->listeners($code)) {
+ $that->emit($code, array($code));
+ return;
+ }
+
+ if (isset($codes[$code])) {
+ $method = $codes[$code];
+ $that->$method($code);
+ return;
+ }
+ };
+
+ $parser->on('csi', $decode);
+ $parser->on('c0', $decode);
+
+ // push resulting data through utf8 sequencer
+ $utf8 = new Utf8Sequencer($parser);
+ $utf8->on('data', function ($data) use ($that, $base) {
+ $that->onFallback($data, $base);
+ });
+
+ // process all stream events (forwarded from input stream)
+ $utf8->on('end', array($this, 'handleEnd'));
+ $utf8->on('error', array($this, 'handleError'));
+ $utf8->on('close', array($this, 'close'));
+ }
+
+ /**
+ * prompt to prepend to input line
+ *
+ * Will redraw the current input prompt with the current input buffer.
+ *
+ * @param string $prompt
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::setPrompt() instead
+ */
+ public function setPrompt($prompt)
+ {
+ if ($prompt === $this->prompt) {
+ return $this;
+ }
+
+ $this->prompt = $prompt;
+
+ return $this->redraw();
+ }
+
+ /**
+ * returns the prompt to prepend to input line
+ *
+ * @return string
+ * @see self::setPrompt()
+ * @deprecated use Stdio::getPrompt() instead
+ */
+ public function getPrompt()
+ {
+ return $this->prompt;
+ }
+
+ /**
+ * sets whether/how to echo text input
+ *
+ * The default setting is `true`, which means that every character will be
+ * echo'ed as-is, i.e. you can see what you're typing.
+ * For example: Typing "test" shows "test".
+ *
+ * You can turn this off by supplying `false`, which means that *nothing*
+ * will be echo'ed while you're typing. This could be a good idea for
+ * password prompts. Note that this could be confusing for users, so using
+ * a character replacement as following is often preferred.
+ * For example: Typing "test" shows "" (nothing).
+ *
+ * Alternative, you can supply a single character replacement character
+ * that will be echo'ed for each character in the text input. This could
+ * be a good idea for password prompts, where an asterisk character ("*")
+ * is often used to indicate typing activity and password length.
+ * For example: Typing "test" shows "****" (with asterisk replacement)
+ *
+ * Changing this setting will redraw the current prompt and echo the current
+ * input buffer according to the new setting.
+ *
+ * @param boolean|string $echo echo can be turned on (boolean true) or off (boolean true), or you can supply a single character replacement string
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::setEcho() instead
+ */
+ public function setEcho($echo)
+ {
+ if ($echo === $this->echo) {
+ return $this;
+ }
+
+ $this->echo = $echo;
+
+ // only redraw if there is any input
+ if ($this->linebuffer !== '') {
+ $this->redraw();
+ }
+
+ return $this;
+ }
+
+ /**
+ * whether or not to support moving cursor left and right
+ *
+ * switching cursor support moves the cursor to the end of the current
+ * input buffer (if any).
+ *
+ * @param boolean $move
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::setMove() instead
+ */
+ public function setMove($move)
+ {
+ $this->move = !!$move;
+
+ return $this->moveCursorTo($this->strlen($this->linebuffer));
+ }
+
+ /**
+ * Gets current cursor position measured in number of text characters.
+ *
+ * Note that the number of text characters doesn't necessarily reflect the
+ * number of monospace cells occupied by the text characters. If you want
+ * to know the latter, use `self::getCursorCell()` instead.
+ *
+ * @return int
+ * @see self::getCursorCell() to get the position measured in monospace cells
+ * @see self::moveCursorTo() to move the cursor to a given character position
+ * @see self::moveCursorBy() to move the cursor by given number of characters
+ * @see self::setMove() to toggle whether the user can move the cursor position
+ * @deprecated use Stdio::getCursorPosition() instead
+ */
+ public function getCursorPosition()
+ {
+ return $this->linepos;
+ }
+
+ /**
+ * Gets current cursor position measured in monospace cells.
+ *
+ * Note that the cell position doesn't necessarily reflect the number of
+ * text characters. If you want to know the latter, use
+ * `self::getCursorPosition()` instead.
+ *
+ * Most "normal" characters occupy a single monospace cell, i.e. the ASCII
+ * sequence for "A" requires a single cell, as do most UTF-8 sequences
+ * like "Ä".
+ *
+ * However, there are a number of code points that do not require a cell
+ * (i.e. invisible surrogates) or require two cells (e.g. some asian glyphs).
+ *
+ * Also note that this takes the echo mode into account, i.e. the cursor is
+ * always at position zero if echo is off. If using a custom echo character
+ * (like asterisk), it will take its width into account instead of the actual
+ * input characters.
+ *
+ * @return int
+ * @see self::getCursorPosition() to get current cursor position measured in characters
+ * @see self::moveCursorTo() to move the cursor to a given character position
+ * @see self::moveCursorBy() to move the cursor by given number of characters
+ * @see self::setMove() to toggle whether the user can move the cursor position
+ * @see self::setEcho()
+ * @deprecated use Stdio::getCursorCell() instead
+ */
+ public function getCursorCell()
+ {
+ if ($this->echo === false) {
+ return 0;
+ }
+ if ($this->echo !== true) {
+ return $this->strwidth($this->echo) * $this->linepos;
+ }
+ return $this->strwidth($this->substr($this->linebuffer, 0, $this->linepos));
+ }
+
+ /**
+ * Moves cursor to right by $n chars (or left if $n is negative).
+ *
+ * Zero value or values out of range (exceeding current input buffer) are
+ * simply ignored.
+ *
+ * Will redraw() the readline only if the visible cell position changes,
+ * see `self::getCursorCell()` for more details.
+ *
+ * @param int $n
+ * @return self
+ * @uses self::moveCursorTo()
+ * @uses self::redraw()
+ * @deprecated use Stdio::moveCursorBy() instead
+ */
+ public function moveCursorBy($n)
+ {
+ return $this->moveCursorTo($this->linepos + $n);
+ }
+
+ /**
+ * Moves cursor to given position in current line buffer.
+ *
+ * Values out of range (exceeding current input buffer) are simply ignored.
+ *
+ * Will redraw() the readline only if the visible cell position changes,
+ * see `self::getCursorCell()` for more details.
+ *
+ * @param int $n
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::moveCursorTo() instead
+ */
+ public function moveCursorTo($n)
+ {
+ if ($n < 0 || $n === $this->linepos || $n > $this->strlen($this->linebuffer)) {
+ return $this;
+ }
+
+ $old = $this->getCursorCell();
+ $this->linepos = $n;
+
+ // only redraw if visible cell position change (implies cursor is actually visible)
+ if ($this->getCursorCell() !== $old) {
+ $this->redraw();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Appends the given input to the current text input buffer at the current position
+ *
+ * This moves the cursor accordingly to the number of characters added.
+ *
+ * @param string $input
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::addInput() instead
+ */
+ public function addInput($input)
+ {
+ if ($input === '') {
+ return $this;
+ }
+
+ // read everything up until before current position
+ $pre = $this->substr($this->linebuffer, 0, $this->linepos);
+ $post = $this->substr($this->linebuffer, $this->linepos);
+
+ $this->linebuffer = $pre . $input . $post;
+ $this->linepos += $this->strlen($input);
+
+ // only redraw if input should be echo'ed (i.e. is not hidden anyway)
+ if ($this->echo !== false) {
+ $this->redraw();
+ }
+
+ return $this;
+ }
+
+ /**
+ * set current text input buffer
+ *
+ * this moves the cursor to the end of the current
+ * input buffer (if any).
+ *
+ * @param string $input
+ * @return self
+ * @uses self::redraw()
+ * @deprecated use Stdio::setInput() instead
+ */
+ public function setInput($input)
+ {
+ if ($this->linebuffer === $input) {
+ return $this;
+ }
+
+ // remember old input length if echo replacement is used
+ $oldlen = (is_string($this->echo)) ? $this->strlen($this->linebuffer) : null;
+
+ $this->linebuffer = $input;
+ $this->linepos = $this->strlen($this->linebuffer);
+
+ // only redraw if input should be echo'ed (i.e. is not hidden anyway)
+ // and echo replacement is used, make sure the input length changes
+ if ($this->echo !== false && $this->linepos !== $oldlen) {
+ $this->redraw();
+ }
+
+ return $this;
+ }
+
+ /**
+ * get current text input buffer
+ *
+ * @return string
+ * @deprecated use Stdio::getInput() instead
+ */
+ public function getInput()
+ {
+ return $this->linebuffer;
+ }
+
+ /**
+ * Adds a new line to the (bottom position of the) history list
+ *
+ * @param string $line
+ * @return self
+ * @uses self::limitHistory() to make sure list does not exceed limits
+ * @deprecated use Stdio::addHistory() instead
+ */
+ public function addHistory($line)
+ {
+ $this->historyLines []= $line;
+
+ return $this->limitHistory($this->historyLimit);
+ }
+
+ /**
+ * Clears the complete history list
+ *
+ * @return self
+ * @deprecated use Stdio::clearHistory() instead
+ */
+ public function clearHistory()
+ {
+ $this->historyLines = array();
+ $this->historyPosition = null;
+
+ if ($this->historyUnsaved !== null) {
+ $this->setInput($this->historyUnsaved);
+ $this->historyUnsaved = null;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns an array with all lines in the history
+ *
+ * @return string[]
+ * @deprecated use Stdio::listHistory() instead
+ */
+ public function listHistory()
+ {
+ return $this->historyLines;
+ }
+
+ /**
+ * Limits the history to a maximum of N entries and truncates the current history list accordingly
+ *
+ * @param int|null $limit
+ * @return self
+ * @deprecated use Stdio::limitHistory() instead
+ */
+ public function limitHistory($limit)
+ {
+ $this->historyLimit = $limit === null ? null : $limit;
+
+ // limit send and currently exceeded
+ if ($this->historyLimit !== null && isset($this->historyLines[$this->historyLimit])) {
+ // adjust position in history according to new position after applying limit
+ if ($this->historyPosition !== null) {
+ $this->historyPosition -= count($this->historyLines) - $this->historyLimit;
+
+ // current position will drop off from list => restore original
+ if ($this->historyPosition < 0) {
+ $this->setInput($this->historyUnsaved);
+ $this->historyPosition = null;
+ $this->historyUnsaved = null;
+ }
+ }
+
+ $this->historyLines = array_slice($this->historyLines, -$this->historyLimit, $this->historyLimit);
+ }
+
+ return $this;
+ }
+
+ /**
+ * set autocompletion handler to use
+ *
+ * The autocomplete handler will be called whenever the user hits the TAB
+ * key.
+ *
+ * @param callable|null $autocomplete
+ * @return self
+ * @throws \InvalidArgumentException if the given callable is invalid
+ * @deprecated use Stdio::setAutocomplete() instead
+ */
+ public function setAutocomplete($autocomplete)
+ {
+ if ($autocomplete !== null && !is_callable($autocomplete)) {
+ throw new \InvalidArgumentException('Invalid autocomplete function given');
+ }
+
+ $this->autocomplete = $autocomplete;
+
+ return $this;
+ }
+
+ /**
+ * Whether or not to emit a audible/visible BELL signal when using a disabled function
+ *
+ * By default, this class will emit a BELL signal when using a disable function,
+ * such as using the <kbd>left</kbd> or <kbd>backspace</kbd> keys when
+ * already at the beginning of the line.
+ *
+ * Whether or not the BELL is audible/visible depends on the termin and its
+ * settings, i.e. some terminals may "beep" or flash the screen or emit a
+ * short vibration.
+ *
+ * @param bool $bell
+ * @return void
+ * @internal use Stdio::setBell() instead
+ */
+ public function setBell($bell)
+ {
+ $this->bell = (bool)$bell;
+ }
+
+ /**
+ * redraw the current input prompt
+ *
+ * Usually, there should be no need to call this method manually. It will
+ * be invoked automatically whenever we detect the readline input needs to
+ * be (re)written to the output.
+ *
+ * Clear the current line and draw the input prompt. If input echo is
+ * enabled, will also draw the current input buffer and move to the current
+ * input buffer position.
+ *
+ * @return self
+ * @internal
+ */
+ public function redraw()
+ {
+ // Erase characters from cursor to end of line and then redraw actual input
+ $this->output->write("\r\033[K" . $this->getDrawString());
+
+ return $this;
+ }
+
+ /**
+ * Returns the string that is used to draw the input prompt
+ *
+ * @return string
+ * @internal
+ */
+ public function getDrawString()
+ {
+ $output = $this->prompt;
+ if ($this->echo !== false) {
+ if ($this->echo === true) {
+ $buffer = $this->linebuffer;
+ } else {
+ $buffer = str_repeat($this->echo, $this->strlen($this->linebuffer));
+ }
+
+ // write output, then move back $reverse chars (by sending backspace)
+ $output .= $buffer . str_repeat("\x08", $this->strwidth($buffer) - $this->getCursorCell());
+ }
+
+ return $output;
+ }
+
+ /** @internal */
+ public function onKeyBackspace()
+ {
+ // left delete only if not at the beginning
+ if ($this->linepos === 0) {
+ $this->bell();
+ } else {
+ $this->deleteChar($this->linepos - 1);
+ }
+ }
+
+ /** @internal */
+ public function onKeyDelete()
+ {
+ // right delete only if not at the end
+ if ($this->isEol()) {
+ $this->bell();
+ } else {
+ $this->deleteChar($this->linepos);
+ }
+ }
+
+ /** @internal */
+ public function onKeyHome()
+ {
+ if ($this->move && $this->linepos !== 0) {
+ $this->moveCursorTo(0);
+ } else {
+ $this->bell();
+ }
+ }
+
+ /** @internal */
+ public function onKeyEnd()
+ {
+ if ($this->move && !$this->isEol()) {
+ $this->moveCursorTo($this->strlen($this->linebuffer));
+ } else {
+ $this->bell();
+ }
+ }
+
+ /** @internal */
+ public function onKeyTab()
+ {
+ if ($this->autocomplete === null) {
+ $this->bell();
+ return;
+ }
+
+ // current word prefix and offset for start of word in input buffer
+ // "echo foo|bar world" will return just "foo" with word offset 5
+ $word = $this->substr($this->linebuffer, 0, $this->linepos);
+ $start = 0;
+ $end = $this->linepos;
+
+ // buffer prefix and postfix for everything that will *not* be matched
+ // above example will return "echo " and "bar world"
+ $prefix = '';
+ $postfix = $this->substr($this->linebuffer, $this->linepos);
+
+ // skip everything before last space
+ $pos = strrpos($word, ' ');
+ if ($pos !== false) {
+ $prefix = (string)substr($word, 0, $pos + 1);
+ $word = (string)substr($word, $pos + 1);
+ $start = $this->strlen($prefix);
+ }
+
+ // skip double quote (") or single quote (') from argument
+ $quote = null;
+ if (isset($word[0]) && ($word[0] === '"' || $word[0] === '\'')) {
+ $quote = $word[0];
+ ++$start;
+ $prefix .= $word[0];
+ $word = (string)substr($word, 1);
+ }
+
+ // invoke autocomplete callback
+ $words = call_user_func($this->autocomplete, $word, $start, $end);
+
+ // return early if autocomplete does not return anything
+ if ($words === null) {
+ return;
+ }
+
+ // remove from list of possible words that do not start with $word or are duplicates
+ $words = array_unique($words);
+ if ($word !== '' && $words) {
+ $words = array_filter($words, function ($w) use ($word) {
+ return strpos($w, $word) === 0;
+ });
+ }
+
+ // return if neither of the possible words match
+ if (!$words) {
+ $this->bell();
+ return;
+ }
+
+ // search longest common prefix among all possible matches
+ $found = reset($words);
+ $all = count($words);
+ if ($all > 1) {
+ while ($found !== '') {
+ // count all words that start with $found
+ $matches = count(array_filter($words, function ($w) use ($found) {
+ return strpos($w, $found) === 0;
+ }));
+
+ // ALL words match $found => common substring found
+ if ($all === $matches) {
+ break;
+ }
+
+ // remove last letter from $found and try again
+ $found = $this->substr($found, 0, -1);
+ }
+
+ // found more than one possible match with this prefix => print options
+ if ($found === $word || $found === '') {
+ // limit number of possible matches
+ if (count($words) > $this->autocompleteSuggestions) {
+ $more = count($words) - ($this->autocompleteSuggestions - 1);
+ $words = array_slice($words, 0, $this->autocompleteSuggestions - 1);
+ $words []= '(+' . $more . ' others)';
+ }
+
+ $this->output->write("\n" . implode(' ', $words) . "\n");
+ $this->redraw();
+
+ return;
+ }
+ }
+
+ if ($quote !== null && $all === 1 && (strpos($postfix, $quote) === false || strpos($postfix, $quote) > strpos($postfix, ' '))) {
+ // add closing quote if word started in quotes and postfix does not already contain closing quote before next space
+ $found .= $quote;
+ } elseif ($found === '') {
+ // add single quotes around empty match
+ $found = '\'\'';
+ }
+
+ if ($postfix === '' && $all === 1) {
+ // append single space after match unless there's a postfix or there are multiple completions
+ $found .= ' ';
+ }
+
+ // replace word in input with best match and adjust cursor
+ $this->linebuffer = $prefix . $found . $postfix;
+ $this->moveCursorBy($this->strlen($found) - $this->strlen($word));
+ }
+
+ /** @internal */
+ public function onKeyEnter()
+ {
+ if ($this->echo !== false) {
+ $this->output->write("\n");
+ }
+ $this->processLine("\n");
+ }
+
+ /** @internal */
+ public function onKeyLeft()
+ {
+ if ($this->move && $this->linepos !== 0) {
+ $this->moveCursorBy(-1);
+ } else {
+ $this->bell();
+ }
+ }
+
+ /** @internal */
+ public function onKeyRight()
+ {
+ if ($this->move && !$this->isEol()) {
+ $this->moveCursorBy(1);
+ } else {
+ $this->bell();
+ }
+ }
+
+ /** @internal */
+ public function onKeyUp()
+ {
+ // ignore if already at top or history is empty
+ if ($this->historyPosition === 0 || !$this->historyLines) {
+ $this->bell();
+ return;
+ }
+
+ if ($this->historyPosition === null) {
+ // first time up => move to last entry
+ $this->historyPosition = count($this->historyLines) - 1;
+ $this->historyUnsaved = $this->getInput();
+ } else {
+ // somewhere in the list => move by one
+ $this->historyPosition--;
+ }
+
+ $this->setInput($this->historyLines[$this->historyPosition]);
+ }
+
+ /** @internal */
+ public function onKeyDown()
+ {
+ // ignore if not currently cycling through history
+ if ($this->historyPosition === null) {
+ $this->bell();
+ return;
+ }
+
+ if (isset($this->historyLines[$this->historyPosition + 1])) {
+ // this is still a valid position => advance by one and apply
+ $this->historyPosition++;
+ $this->setInput($this->historyLines[$this->historyPosition]);
+ } else {
+ // moved beyond bottom => restore original unsaved input
+ $this->setInput($this->historyUnsaved);
+ $this->historyPosition = null;
+ $this->historyUnsaved = null;
+ }
+ }
+
+ /**
+ * Will be invoked for character(s) that could not otherwise be processed by the sequencer
+ *
+ * @internal
+ */
+ public function onFallback($chars, EventEmitterInterface $base = null)
+ {
+ // check if there's any special key binding for any of the chars
+ $buffer = '';
+ foreach ($this->strsplit($chars) as $char) {
+ // forward compatibility: check if any key binding exists on base Stdio instance
+ // deprecated: check if any key binding exists on this Readline instance
+ $emit = null;
+ if ($base !== null && $base->listeners($char)) {
+ $emit = $base;
+ } else if ($this->listeners($char)) {
+ $emit = $this;
+ }
+
+ if ($emit !== null) {
+ // special key binding for this character found
+ // process all characters before this one before invoking function
+ if ($buffer !== '') {
+ $this->addInput($buffer);
+ $buffer = '';
+ }
+ $emit->emit($char, array($char));
+ } else {
+ $buffer .= $char;
+ }
+ }
+
+ // process remaining input characters after last special key binding
+ if ($buffer !== '') {
+ $this->addInput($buffer);
+ }
+ }
+
+ /**
+ * delete a character at the given position
+ *
+ * Removing a character left to the current cursor will also move the cursor
+ * to the left.
+ *
+ * @param int $n
+ */
+ private function deleteChar($n)
+ {
+ // read everything up until before current position
+ $pre = $this->substr($this->linebuffer, 0, $n);
+ $post = $this->substr($this->linebuffer, $n + 1);
+
+ $this->linebuffer = $pre . $post;
+
+ // move cursor one cell to the left if we're deleting in front of the cursor
+ if ($n < $this->linepos) {
+ --$this->linepos;
+ }
+
+ $this->redraw();
+ }
+
+ /**
+ * process the current line buffer, emit event and redraw empty line
+ *
+ * @uses self::setInput()
+ */
+ protected function processLine($eol)
+ {
+ // reset history cycle position
+ $this->historyPosition = null;
+ $this->historyUnsaved = null;
+
+ // store and reset/clear/redraw current input
+ $line = $this->linebuffer;
+ if ($line !== '') {
+ // the line is not empty, reset it (and implicitly redraw prompt)
+ $this->setInput('');
+ } elseif ($this->echo !== false) {
+ // explicitly redraw prompt after empty line
+ $this->redraw();
+ }
+
+ // process stored input buffer
+ $this->emit('data', array($line . $eol));
+ }
+
+ /**
+ * @param string $str
+ * @return int
+ * @codeCoverageIgnore
+ */
+ private function strlen($str)
+ {
+ // prefer mb_strlen() if available
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($str, $this->encoding);
+ }
+
+ // otherwise replace all unicode chars with dots and count dots
+ return strlen(preg_replace('/./us', '.', $str));
+ }
+
+ /**
+ * @param string $str
+ * @param int $start
+ * @param ?int $len
+ * @return string
+ * @codeCoverageIgnore
+ */
+ private function substr($str, $start = 0, $len = null)
+ {
+ if ($len === null) {
+ $len = $this->strlen($str) - $start;
+ }
+
+ // prefer mb_substr() if available
+ if (function_exists('mb_substr')) {
+ return (string)mb_substr($str, $start, $len, $this->encoding);
+ }
+
+ // otherwise build array with all unicode chars and slice array
+ preg_match_all('/./us', $str, $matches);
+
+ return implode('', array_slice($matches[0], $start, $len));
+ }
+
+ /**
+ * @internal
+ * @param string $str
+ * @return int
+ * @codeCoverageIgnore
+ */
+ public function strwidth($str)
+ {
+ // prefer mb_strwidth() if available
+ if (function_exists('mb_strwidth')) {
+ return mb_strwidth($str, $this->encoding);
+ }
+
+ // otherwise replace each double-width unicode graphemes with two dots, all others with single dot and count number of dots
+ // mbstring's list of double-width graphemes is *very* long: https://3v4l.org/GEg3u
+ // let's use symfony's list from https://github.com/symfony/polyfill-mbstring/blob/e79d363049d1c2128f133a2667e4f4190904f7f4/Mbstring.php#L523
+ // which looks like they originally came from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ return strlen(preg_replace(
+ array(
+ '/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u',
+ '/./us',
+ ),
+ array(
+ '..',
+ '.',
+ ),
+ $str
+ ));
+ }
+
+ /**
+ * @param string $str
+ * @return string[]
+ */
+ private function strsplit($str)
+ {
+ return preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
+ }
+
+ /**
+ * @return bool
+ */
+ private function isEol()
+ {
+ return $this->linepos === $this->strlen($this->linebuffer);
+ }
+
+ /**
+ * @return void
+ */
+ private function bell()
+ {
+ if ($this->bell) {
+ $this->output->write("\x07"); // BEL a.k.a. \a
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if ($this->linebuffer !== '') {
+ $this->processLine('');
+ }
+
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->emit('error', array($error));
+ $this->close();
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+}
diff --git a/vendor/clue/stdio-react/src/Stdio.php b/vendor/clue/stdio-react/src/Stdio.php
new file mode 100644
index 0000000..aff2959
--- /dev/null
+++ b/vendor/clue/stdio-react/src/Stdio.php
@@ -0,0 +1,630 @@
+<?php
+
+namespace Clue\React\Stdio;
+
+use Evenement\EventEmitter;
+use React\EventLoop\LoopInterface;
+use React\Stream\DuplexStreamInterface;
+use React\Stream\ReadableResourceStream;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableResourceStream;
+use React\Stream\WritableStreamInterface;
+
+class Stdio extends EventEmitter implements DuplexStreamInterface
+{
+ private $input;
+ private $output;
+ private $readline;
+
+ private $ending = false;
+ private $closed = false;
+ private $incompleteLine = '';
+ private $originalTtyMode = null;
+
+ /**
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param ?LoopInterface $loop
+ * @param ?ReadableStreamInterface $input
+ * @param ?WritableStreamInterface $output
+ * @param ?Readline $readline
+ */
+ public function __construct(LoopInterface $loop = null, ReadableStreamInterface $input = null, WritableStreamInterface $output = null, Readline $readline = null)
+ {
+ if ($input === null) {
+ $input = $this->createStdin($loop); // @codeCoverageIgnore
+ }
+
+ if ($output === null) {
+ $output = $this->createStdout($loop); // @codeCoverageIgnore
+ }
+
+ if ($readline === null) {
+ $readline = new Readline($input, $output, $this);
+ }
+
+ $this->input = $input;
+ $this->output = $output;
+ $this->readline = $readline;
+
+ $that = $this;
+
+ // readline data emits a new line
+ $incomplete =& $this->incompleteLine;
+ $this->readline->on('data', function($line) use ($that, &$incomplete) {
+ // readline emits a new line on enter, so start with a blank line
+ $incomplete = '';
+ $that->emit('data', array($line));
+ });
+
+ // handle all input events (readline forwards all input events)
+ $this->readline->on('error', array($this, 'handleError'));
+ $this->readline->on('end', array($this, 'handleEnd'));
+ $this->readline->on('close', array($this, 'handleCloseInput'));
+
+ // handle all output events
+ $this->output->on('error', array($this, 'handleError'));
+ $this->output->on('close', array($this, 'handleCloseOutput'));
+ }
+
+ public function __destruct()
+ {
+ $this->restoreTtyMode();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function isReadable()
+ {
+ return $this->input->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->output->isWritable();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function write($data)
+ {
+ // return false if already ended, return true if writing empty string
+ if ($this->ending || $data === '') {
+ return !$this->ending;
+ }
+
+ $out = $data;
+
+ $lastNewline = strrpos($data, "\n");
+
+ $restoreReadline = false;
+
+ if ($this->incompleteLine !== '') {
+ // the last write did not end with a newline => append to existing row
+
+ // move one line up and move cursor to last position before writing data
+ $out = "\033[A" . "\r\033[" . $this->width($this->incompleteLine) . "C" . $out;
+
+ // data contains a newline, so this will overwrite the readline prompt
+ if ($lastNewline !== false) {
+ // move cursor to beginning of readline prompt and clear line
+ // clearing is important because $data may not overwrite the whole line
+ $out = "\r\033[K" . $out;
+
+ // make sure to restore readline after this output
+ $restoreReadline = true;
+ }
+ } else {
+ // here, we're writing to a new line => overwrite readline prompt
+
+ // move cursor to beginning of readline prompt and clear line
+ $out = "\r\033[K" . $out;
+
+ // we always overwrite the readline prompt, so restore it on next line
+ $restoreReadline = true;
+ }
+
+ // following write will have have to append to this line if it does not end with a newline
+ $endsWithNewline = substr($data, -1) === "\n";
+
+ if ($endsWithNewline) {
+ // line ends with newline, so this is line is considered complete
+ $this->incompleteLine = '';
+ } else {
+ // always end data with newline in order to append readline on next line
+ $out .= "\n";
+
+ if ($lastNewline === false) {
+ // contains no newline at all, everything is incomplete
+ $this->incompleteLine .= $data;
+ } else {
+ // contains a newline, everything behind it is incomplete
+ $this->incompleteLine = (string)substr($data, $lastNewline + 1);
+ }
+ }
+
+ if ($restoreReadline) {
+ // write output and restore original readline prompt and line buffer
+ return $this->output->write($out . $this->readline->getDrawString());
+ } else {
+ // restore original cursor position in readline prompt
+ $pos = $this->width($this->readline->getPrompt()) + $this->readline->getCursorCell();
+ if ($pos !== 0) {
+ // we always start at beginning of line, move right by X
+ $out .= "\033[" . $pos . "C";
+ }
+
+ // write to actual output stream
+ return $this->output->write($out);
+ }
+ }
+
+ public function end($data = null)
+ {
+ if ($this->ending) {
+ return;
+ }
+
+ if ($data !== null) {
+ $this->write($data);
+ }
+
+ $this->ending = true;
+
+ // clear readline output, close input and end output
+ $this->readline->setInput('')->setPrompt('');
+ $this->input->close();
+ $this->output->end();
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->ending = true;
+ $this->closed = true;
+
+ $this->input->close();
+ $this->output->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /**
+ * @deprecated
+ * @return Readline
+ */
+ public function getReadline()
+ {
+ return $this->readline;
+ }
+
+
+ /**
+ * prompt to prepend to input line
+ *
+ * Will redraw the current input prompt with the current input buffer.
+ *
+ * @param string $prompt
+ * @return void
+ */
+ public function setPrompt($prompt)
+ {
+ $this->readline->setPrompt($prompt);
+ }
+
+ /**
+ * returns the prompt to prepend to input line
+ *
+ * @return string
+ * @see self::setPrompt()
+ */
+ public function getPrompt()
+ {
+ return $this->readline->getPrompt();
+ }
+
+ /**
+ * sets whether/how to echo text input
+ *
+ * The default setting is `true`, which means that every character will be
+ * echo'ed as-is, i.e. you can see what you're typing.
+ * For example: Typing "test" shows "test".
+ *
+ * You can turn this off by supplying `false`, which means that *nothing*
+ * will be echo'ed while you're typing. This could be a good idea for
+ * password prompts. Note that this could be confusing for users, so using
+ * a character replacement as following is often preferred.
+ * For example: Typing "test" shows "" (nothing).
+ *
+ * Alternative, you can supply a single character replacement character
+ * that will be echo'ed for each character in the text input. This could
+ * be a good idea for password prompts, where an asterisk character ("*")
+ * is often used to indicate typing activity and password length.
+ * For example: Typing "test" shows "****" (with asterisk replacement)
+ *
+ * Changing this setting will redraw the current prompt and echo the current
+ * input buffer according to the new setting.
+ *
+ * @param boolean|string $echo echo can be turned on (boolean true) or off (boolean true), or you can supply a single character replacement string
+ * @return void
+ */
+ public function setEcho($echo)
+ {
+ $this->readline->setEcho($echo);
+ }
+
+ /**
+ * whether or not to support moving cursor left and right
+ *
+ * switching cursor support moves the cursor to the end of the current
+ * input buffer (if any).
+ *
+ * @param boolean $move
+ * @return void
+ */
+ public function setMove($move)
+ {
+ $this->readline->setMove($move);
+ }
+
+ /**
+ * Gets current cursor position measured in number of text characters.
+ *
+ * Note that the number of text characters doesn't necessarily reflect the
+ * number of monospace cells occupied by the text characters. If you want
+ * to know the latter, use `self::getCursorCell()` instead.
+ *
+ * @return int
+ * @see self::getCursorCell() to get the position measured in monospace cells
+ * @see self::moveCursorTo() to move the cursor to a given character position
+ * @see self::moveCursorBy() to move the cursor by given number of characters
+ * @see self::setMove() to toggle whether the user can move the cursor position
+ */
+ public function getCursorPosition()
+ {
+ return $this->readline->getCursorPosition();
+ }
+
+ /**
+ * Gets current cursor position measured in monospace cells.
+ *
+ * Note that the cell position doesn't necessarily reflect the number of
+ * text characters. If you want to know the latter, use
+ * `self::getCursorPosition()` instead.
+ *
+ * Most "normal" characters occupy a single monospace cell, i.e. the ASCII
+ * sequence for "A" requires a single cell, as do most UTF-8 sequences
+ * like "Ä".
+ *
+ * However, there are a number of code points that do not require a cell
+ * (i.e. invisible surrogates) or require two cells (e.g. some asian glyphs).
+ *
+ * Also note that this takes the echo mode into account, i.e. the cursor is
+ * always at position zero if echo is off. If using a custom echo character
+ * (like asterisk), it will take its width into account instead of the actual
+ * input characters.
+ *
+ * @return int
+ * @see self::getCursorPosition() to get current cursor position measured in characters
+ * @see self::moveCursorTo() to move the cursor to a given character position
+ * @see self::moveCursorBy() to move the cursor by given number of characters
+ * @see self::setMove() to toggle whether the user can move the cursor position
+ * @see self::setEcho()
+ */
+ public function getCursorCell()
+ {
+ return $this->readline->getCursorCell();
+ }
+
+ /**
+ * Moves cursor to right by $n chars (or left if $n is negative).
+ *
+ * Zero value or values out of range (exceeding current input buffer) are
+ * simply ignored.
+ *
+ * Will redraw() the readline only if the visible cell position changes,
+ * see `self::getCursorCell()` for more details.
+ *
+ * @param int $n
+ * @return void
+ */
+ public function moveCursorBy($n)
+ {
+ $this->readline->moveCursorBy($n);
+ }
+
+ /**
+ * Moves cursor to given position in current line buffer.
+ *
+ * Values out of range (exceeding current input buffer) are simply ignored.
+ *
+ * Will redraw() the readline only if the visible cell position changes,
+ * see `self::getCursorCell()` for more details.
+ *
+ * @param int $n
+ * @return void
+ */
+ public function moveCursorTo($n)
+ {
+ $this->readline->moveCursorTo($n);
+ }
+
+ /**
+ * Appends the given input to the current text input buffer at the current position
+ *
+ * This moves the cursor accordingly to the number of characters added.
+ *
+ * @param string $input
+ * @return void
+ */
+ public function addInput($input)
+ {
+ $this->readline->addInput($input);
+ }
+
+ /**
+ * set current text input buffer
+ *
+ * this moves the cursor to the end of the current
+ * input buffer (if any).
+ *
+ * @param string $input
+ * @return void
+ */
+ public function setInput($input)
+ {
+ $this->readline->setInput($input);
+ }
+
+ /**
+ * get current text input buffer
+ *
+ * @return string
+ */
+ public function getInput()
+ {
+ return $this->readline->getInput();
+ }
+
+ /**
+ * Adds a new line to the (bottom position of the) history list
+ *
+ * @param string $line
+ * @return void
+ */
+ public function addHistory($line)
+ {
+ $this->readline->addHistory($line);
+ }
+
+ /**
+ * Clears the complete history list
+ *
+ * @return void
+ */
+ public function clearHistory()
+ {
+ $this->readline->clearHistory();
+ }
+
+ /**
+ * Returns an array with all lines in the history
+ *
+ * @return string[]
+ */
+ public function listHistory()
+ {
+ return $this->readline->listHistory();
+ }
+
+ /**
+ * Limits the history to a maximum of N entries and truncates the current history list accordingly
+ *
+ * @param int|null $limit
+ * @return void
+ */
+ public function limitHistory($limit)
+ {
+ $this->readline->limitHistory($limit);
+ }
+
+ /**
+ * set autocompletion handler to use
+ *
+ * The autocomplete handler will be called whenever the user hits the TAB
+ * key.
+ *
+ * @param callable|null $autocomplete
+ * @return void
+ * @throws \InvalidArgumentException if the given callable is invalid
+ */
+ public function setAutocomplete($autocomplete)
+ {
+ $this->readline->setAutocomplete($autocomplete);
+ }
+
+ /**
+ * whether or not to emit a audible/visible BELL signal when using a disabled function
+ *
+ * By default, this class will emit a BELL signal when using a disable function,
+ * such as using the <kbd>left</kbd> or <kbd>backspace</kbd> keys when
+ * already at the beginning of the line.
+ *
+ * Whether or not the BELL is audible/visible depends on the termin and its
+ * settings, i.e. some terminals may "beep" or flash the screen or emit a
+ * short vibration.
+ *
+ * @param bool $bell
+ * @return void
+ */
+ public function setBell($bell)
+ {
+ $this->readline->setBell($bell);
+ }
+
+ private function width($str)
+ {
+ return $this->readline->strwidth($str) - 2 * substr_count($str, "\x08");
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->emit('end');
+ }
+
+ /** @internal */
+ public function handleCloseInput()
+ {
+ $this->restoreTtyMode();
+
+ if (!$this->output->isWritable()) {
+ $this->close();
+ }
+ }
+
+ /** @internal */
+ public function handleCloseOutput()
+ {
+ if (!$this->input->isReadable()) {
+ $this->close();
+ }
+ }
+
+ /**
+ * @codeCoverageIgnore this is covered by functional tests with/without ext-readline
+ */
+ private function restoreTtyMode()
+ {
+ if (function_exists('readline_callback_handler_remove')) {
+ // remove dummy readline handler to turn to default input mode
+ readline_callback_handler_remove();
+ } elseif ($this->originalTtyMode !== null && is_resource(STDIN) && $this->isTty()) {
+ // Reset stty so it behaves normally again
+ shell_exec('stty ' . escapeshellarg($this->originalTtyMode));
+ $this->originalTtyMode = null;
+ }
+
+ // restore blocking mode so following programs behave normally
+ if (defined('STDIN') && is_resource(STDIN)) {
+ stream_set_blocking(STDIN, true);
+ }
+ }
+
+ /**
+ * @param ?LoopInterface $loop
+ * @return ReadableStreamInterface
+ * @codeCoverageIgnore this is covered by functional tests with/without ext-readline
+ */
+ private function createStdin(LoopInterface $loop = null)
+ {
+ // STDIN not defined ("php -a") or already closed (`fclose(STDIN)`)
+ // also support starting program with closed STDIN ("example.php 0<&-")
+ // the stream is a valid resource and is not EOF, but fstat fails
+ if (!defined('STDIN') || !is_resource(STDIN) || fstat(STDIN) === false) {
+ $stream = new ReadableResourceStream(fopen('php://memory', 'r'), $loop);
+ $stream->close();
+ return $stream;
+ }
+
+ $stream = new ReadableResourceStream(STDIN, $loop);
+
+ if (function_exists('readline_callback_handler_install')) {
+ // Prefer `ext-readline` to install dummy handler to turn on raw input mode.
+ // We will never actually feed the readline handler and instead
+ // handle all input in our `Readline` implementation.
+ readline_callback_handler_install('', function () { });
+ return $stream;
+ }
+
+ if ($this->isTty()) {
+ $this->originalTtyMode = rtrim(shell_exec('stty -g'), PHP_EOL);
+
+ // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
+ shell_exec('stty -icanon -echo');
+ }
+
+ // register shutdown function to restore TTY mode in case of unclean shutdown (uncaught exception)
+ // this will not trigger on SIGKILL etc., but the terminal should take care of this
+ register_shutdown_function(array($this, 'close'));
+
+ return $stream;
+ }
+
+ /**
+ * @param ?LoopInterface $loop
+ * @return WritableStreamInterface
+ * @codeCoverageIgnore this is covered by functional tests
+ */
+ private function createStdout(LoopInterface $loop = null)
+ {
+ // STDOUT not defined ("php -a") or already closed (`fclose(STDOUT)`)
+ // also support starting program with closed STDOUT ("example.php >&-")
+ // the stream is a valid resource and is not EOF, but fstat fails
+ if (!defined('STDOUT') || !is_resource(STDOUT) || fstat(STDOUT) === false) {
+ $output = new WritableResourceStream(fopen('php://memory', 'r+'), $loop);
+ $output->close();
+ } else {
+ $output = new WritableResourceStream(STDOUT, $loop);
+ }
+
+ return $output;
+ }
+
+ /**
+ * @return bool
+ * @codeCoverageIgnore
+ */
+ private function isTty()
+ {
+ if (PHP_VERSION_ID >= 70200) {
+ // Prefer `stream_isatty()` (available as of PHP 7.2 only)
+ return stream_isatty(STDIN);
+ } elseif (function_exists('posix_isatty')) {
+ // Otherwise use `posix_isatty` if available (requires `ext-posix`)
+ return posix_isatty(STDIN);
+ }
+
+ // otherwise try to guess based on stat file mode and device major number
+ // Must be special character device: ($mode & S_IFMT) === S_IFCHR
+ // And device major number must be allocated to TTYs (2-5 and 128-143)
+ // For what it's worth, checking for device gid 5 (tty) is less reliable.
+ // @link http://man7.org/linux/man-pages/man7/inode.7.html
+ // @link https://www.kernel.org/doc/html/v4.11/admin-guide/devices.html#terminal-devices
+ $stat = fstat(STDIN);
+ $mode = isset($stat['mode']) ? ($stat['mode'] & 0170000) : 0;
+ $major = isset($stat['dev']) ? (($stat['dev'] >> 8) & 0xff) : 0;
+
+ return ($mode === 0020000 && $major >= 2 && $major <= 143 && ($major <=5 || $major >= 128));
+ }
+}
diff --git a/vendor/clue/term-react/LICENSE b/vendor/clue/term-react/LICENSE
new file mode 100644
index 0000000..7baae8e
--- /dev/null
+++ b/vendor/clue/term-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Christian Lück
+
+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/clue/term-react/composer.json b/vendor/clue/term-react/composer.json
new file mode 100644
index 0000000..d1b3ce5
--- /dev/null
+++ b/vendor/clue/term-react/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "clue/term-react",
+ "description": "Streaming terminal emulator, built on top of ReactPHP.",
+ "keywords": ["terminal", "control codes", "xterm", "ANSI", "ASCII", "VT100", "csi", "osc", "apc", "dps", "pm", "C1", "C0", "streaming", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-term",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\Term\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Term\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3"
+ }
+}
diff --git a/vendor/clue/term-react/src/ControlCodeParser.php b/vendor/clue/term-react/src/ControlCodeParser.php
new file mode 100644
index 0000000..abbe400
--- /dev/null
+++ b/vendor/clue/term-react/src/ControlCodeParser.php
@@ -0,0 +1,223 @@
+<?php
+
+namespace Clue\React\Term;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\WritableStreamInterface;
+use React\Stream\Util;
+
+class ControlCodeParser extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $closed = false;
+ private $buffer = '';
+
+ /**
+ * we know about the following C1 types (7 bit only)
+ *
+ * followed by "[" means it's CSI (Control Sequence Introducer)
+ * followed by "]" means it's OSC (Operating System Controls)
+ * followed by "_" means it's APC (Application Program-Control)
+ * followed by "P" means it's DPS (Device-Control string)
+ * followed by "^" means it's PM (Privacy Message)
+ *
+ * Each of these will be parsed until the sequence ends and then emitted
+ * under their respective name.
+ *
+ * All other C1 types will be emitted under the "c1" name without any
+ * further processing.
+ *
+ * C1 types in 8 bit are currently not supported, as they require special
+ * care with regards to whether UTF-8 mode is enabled. So far this has
+ * turned out to be a non-issue because most terminal emulators *accept*
+ * boths formats, but usually *send* in 7 bit mode exclusively.
+ */
+ private $types = array(
+ '[' => 'csi',
+ ']' => 'osc',
+ '_' => 'apc',
+ 'P' => 'dps',
+ '^' => 'pm',
+ );
+
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ if (!$this->input->isReadable()) {
+ return $this->close();
+ }
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->buffer = '';
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ while ($this->buffer !== '') {
+ // search for first control character (C0 and DEL)
+ $c0 = false;
+ for ($i = 0; isset($this->buffer[$i]); ++$i) {
+ $code = ord($this->buffer[$i]);
+ if ($code < 0x20 || $code === 0x7F) {
+ $c0 = $i;
+ break;
+ }
+ }
+
+ // no C0 found, emit whole buffer as data
+ if ($c0 === false) {
+ $data = $this->buffer;
+ $this->buffer = '';
+
+ $this->emit('data', array($data));
+ return;
+ }
+
+ // C0 found somewhere inbetween, emit everything before C0 as data
+ if ($c0 !== 0) {
+ $data = substr($this->buffer, 0, $c0);
+ $this->buffer = substr($this->buffer, $c0);
+
+ $this->emit('data', array($data));
+ continue;
+ }
+
+ // C0 is now at start of buffer
+ // check if this is a normal C0 code or an ESC (\x1B = \033)
+ // normal C0 will be emitted, ESC will be parsed further
+ if ($this->buffer[0] !== "\x1B") {
+ $data = $this->buffer[0];
+ $this->buffer = (string)substr($this->buffer, 1);
+
+ $this->emit('c0', array($data));
+ continue;
+ }
+
+ // check following byte to determine type
+ if (!isset($this->buffer[1])) {
+ // type currently unknown, wait for next data chunk
+ break;
+ }
+
+ // if this is an unknown type, just emit as "c1" without further parsing
+ if (!isset($this->types[$this->buffer[1]])) {
+ $data = substr($this->buffer, 0, 2);
+ $this->buffer = (string)substr($this->buffer, 2);
+
+ $this->emit('c1', array($data));
+ continue;
+ }
+
+ // this is known type, check for the sequence end
+ $type = $this->types[$this->buffer[1]];
+ $found = false;
+
+ if ($type === 'csi') {
+ // CSI is now at the start of the buffer, search final character
+ for ($i = 2; isset($this->buffer[$i]); ++$i) {
+ $code = ord($this->buffer[$i]);
+
+ // final character between \x40-\x7E
+ if ($code >= 64 && $code <= 126) {
+ $data = substr($this->buffer, 0, $i + 1);
+ $this->buffer = (string)substr($this->buffer, $i + 1);
+
+ $this->emit($type, array($data));
+ $found = true;
+ break;
+ }
+ }
+ } else {
+ // all other types are terminated by ST
+ // only OSC can also be terminted by BEL (whichever comes first)
+ $st = strpos($this->buffer, "\x1B\\");
+ $bel = ($type === 'osc') ? strpos($this->buffer, "\x07") : false;
+
+ if ($st !== false && ($bel === false || $bel > $st)) {
+ // ST comes before BEL or no BEL found
+ $data = substr($this->buffer, 0, $st + 2);
+ $this->buffer = (string)substr($this->buffer, $st + 2);
+
+ $this->emit($type, array($data));
+ $found = true;
+ } elseif ($bel !== false) {
+ // BEL comes before ST or no ST found
+ $data = substr($this->buffer, 0, $bel + 1);
+ $this->buffer = (string)substr($this->buffer, $bel + 1);
+
+ $this->emit($type, array($data));
+ $found = true;
+ }
+ }
+
+ // no final character found => wait for next data chunk
+ if (!$found) {
+ break;
+ }
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if (!$this->closed) {
+ if ($this->buffer === '') {
+ $this->emit('end');
+ } else {
+ $this->emit('error', array(new \RuntimeException('Stream ended with incomplete control code sequence in buffer')));
+ }
+ $this->close();
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+}
diff --git a/vendor/clue/utf8-react/LICENSE b/vendor/clue/utf8-react/LICENSE
new file mode 100644
index 0000000..7baae8e
--- /dev/null
+++ b/vendor/clue/utf8-react/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Christian Lück
+
+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/clue/utf8-react/composer.json b/vendor/clue/utf8-react/composer.json
new file mode 100644
index 0000000..931708f
--- /dev/null
+++ b/vendor/clue/utf8-react/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "clue/utf8-react",
+ "description": "Streaming UTF-8 parser, built on top of ReactPHP.",
+ "keywords": ["UTF-8", "utf8", "unicode", "streaming", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-utf8",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\Utf8\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Utf8\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4 || ^0.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 ||^5.7 || ^4.8",
+ "react/stream": "^1.0 || ^0.7"
+ }
+}
diff --git a/vendor/clue/utf8-react/src/Sequencer.php b/vendor/clue/utf8-react/src/Sequencer.php
new file mode 100644
index 0000000..e9bf433
--- /dev/null
+++ b/vendor/clue/utf8-react/src/Sequencer.php
@@ -0,0 +1,174 @@
+<?php
+
+namespace Clue\React\Utf8;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\WritableStreamInterface;
+use React\Stream\Util;
+
+/**
+ * forwards only complete UTF-8 sequences
+ */
+class Sequencer extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $invalid;
+
+ private $buffer = '';
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $input, $replacementCharacter = '?')
+ {
+ $this->input = $input;
+ $this->invalid = $replacementCharacter;
+
+ if (!$input->isReadable()) {
+ return $this->close();
+ }
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+ $len = strlen($this->buffer);
+
+ $sequence = '';
+ $expect = 0;
+ $out = '';
+
+ for ($i = 0; $i < $len; ++$i) {
+ $char = $this->buffer[$i];
+ $code = ord($char);
+
+ if ($code & 128) {
+ // multi-byte sequence
+ if ($code & 64) {
+ // this is the start of a sequence
+
+ // unexpected start of sequence because already within sequence
+ if ($expect !== 0) {
+ $out .= str_repeat($this->invalid, strlen($sequence));
+ $sequence = '';
+ }
+
+ $sequence = $char;
+ $expect = 2;
+
+ if ($code & 32) {
+ ++$expect;
+ if ($code & 16) {
+ ++$expect;
+
+ if ($code & 8) {
+ // invalid sequence start length
+ $out .= $this->invalid;
+ $sequence = '';
+ $expect = 0;
+ }
+ }
+ }
+ } else {
+ // this is a follow-up byte in a sequence
+ if ($expect === 0) {
+ // we're not within a sequence in first place
+ $out .= $this->invalid;
+ } else {
+ // valid following byte in sequence
+ $sequence .= $char;
+
+ // sequence reached expected length => add to output
+ if (strlen($sequence) === $expect) {
+ $out .= $sequence;
+ $sequence = '';
+ $expect = 0;
+ }
+ }
+ }
+ } else {
+ // simple ASCII character found
+
+ // unexpected because already within sequence
+ if ($expect !== 0) {
+ $out .= str_repeat($this->invalid, strlen($sequence));
+ $sequence = '';
+ $expect = 0;
+ }
+
+ $out .= $char;
+ }
+ }
+
+ if ($out !== '') {
+ $this->buffer = substr($this->buffer, strlen($out));
+
+ $this->emit('data', array($out));
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if ($this->buffer !== '' && $this->invalid !== '') {
+ $data = str_repeat($this->invalid, strlen($this->buffer));
+ $this->buffer = '';
+
+ $this->emit('data', array($data));
+ }
+
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->emit('error', array($error));
+ $this->close();
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->buffer = '';
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+}
diff --git a/vendor/components/jquery/bower.json b/vendor/components/jquery/bower.json
new file mode 100644
index 0000000..2f0e2e1
--- /dev/null
+++ b/vendor/components/jquery/bower.json
@@ -0,0 +1,16 @@
+{
+ "name": "jquery",
+ "version": "3.5.1",
+ "description": "jQuery component",
+ "license": "MIT",
+ "keywords": [
+ "jquery",
+ "component"
+ ],
+ "main": "jquery.js",
+ "ignore": [
+ "component.json",
+ "package.json",
+ "composer.json"
+ ]
+}
diff --git a/vendor/components/jquery/component.json b/vendor/components/jquery/component.json
new file mode 100644
index 0000000..0fa35fd
--- /dev/null
+++ b/vendor/components/jquery/component.json
@@ -0,0 +1,22 @@
+{
+ "name": "jquery",
+ "repo": "components/jquery",
+ "version": "3.5.1",
+ "description": "jQuery component",
+ "license": "MIT",
+ "keywords": [
+ "jquery",
+ "component"
+ ],
+ "main": "jquery.js",
+ "scripts": [
+ "jquery.js",
+ "jquery.min.js",
+ "jquery.slim.js",
+ "jquery.slim.min.js"
+ ],
+ "files": [
+ "jquery.min.map",
+ "jquery.slim.min.map"
+ ]
+}
diff --git a/vendor/components/jquery/composer.json b/vendor/components/jquery/composer.json
new file mode 100644
index 0000000..8a779ad
--- /dev/null
+++ b/vendor/components/jquery/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "components/jquery",
+ "description": "jQuery JavaScript Library",
+ "type": "component",
+ "homepage": "http://jquery.com",
+ "license": "MIT",
+ "support": {
+ "irc": "irc://irc.freenode.org/jquery",
+ "issues": "https://github.com/jquery/jquery/issues",
+ "forum": "http://forum.jquery.com",
+ "wiki": "http://docs.jquery.com/",
+ "source": "https://github.com/jquery/jquery"
+ },
+ "authors": [
+ {
+ "name": "JS Foundation and other contributors",
+ "url": "https://github.com/jquery/jquery/blob/master/AUTHORS.txt"
+ }
+ ],
+ "extra": {
+ "component": {
+ "scripts": [
+ "jquery.js"
+ ],
+ "files": [
+ "jquery.min.js",
+ "jquery.min.map",
+ "jquery.slim.js",
+ "jquery.slim.min.js",
+ "jquery.slim.min.map"
+ ]
+ }
+ }
+}
diff --git a/vendor/components/jquery/package.json b/vendor/components/jquery/package.json
new file mode 100644
index 0000000..f9385dc
--- /dev/null
+++ b/vendor/components/jquery/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "jquery",
+ "description": "JavaScript library for DOM operations",
+ "version": "3.5.1",
+ "homepage": "http://jquery.com",
+ "author": {
+ "name": "jQuery Foundation and other contributors",
+ "url": "https://github.com/jquery/jquery/blob/master/AUTHORS.txt"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jquery/jquery.git"
+ },
+ "keywords": [
+ "jquery",
+ "javascript",
+ "browser",
+ "library"
+ ],
+ "bugs": {
+ "url": "https://github.com/jquery/jquery/issues"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/jquery/jquery/blob/master/LICENSE.txt"
+ }
+ ],
+ "spm": {
+ "main": "jquery.js"
+ }
+}
+
diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php
new file mode 100644
index 0000000..afef3fa
--- /dev/null
+++ b/vendor/composer/ClassLoader.php
@@ -0,0 +1,572 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var ?string */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<string, int>>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<int, string>>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, string>
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * @var array[]
+ * @psalm-var array<string, array<string, string[]>>
+ */
+ private $prefixesPsr0 = array();
+ /**
+ * @var array[]
+ * @psalm-var array<string, string>
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var string[]
+ * @psalm-var array<string, string>
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var bool[]
+ * @psalm-var array<string, bool>
+ */
+ private $missingClasses = array();
+
+ /** @var ?string */
+ private $apcuPrefix;
+
+ /**
+ * @var self[]
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param ?string $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, array<int, string>>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, string>
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return array<string, string>
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return string[] Array of classname => path
+ * @psalm-return array<string, string>
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param string[] $classMap Class to filename map
+ * @psalm-param array<string, string> $classMap
+ *
+ * @return void
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @return void
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param string[]|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param string[]|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ *
+ * @return void
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ *
+ * @return void
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the currently registered loaders indexed by their corresponding vendor directories.
+ *
+ * @return self[]
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param string $file
+ * @return void
+ * @private
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php
new file mode 100644
index 0000000..41bc143
--- /dev/null
+++ b/vendor/composer/InstalledVersions.php
@@ -0,0 +1,352 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|null
+ * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
+ */
+ private static $installed;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+ */
+ private static $installedByVendor = array();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints($constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
+ */
+ public static function getRootPackage()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+ * @return array[]
+ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
+ */
+ public static function getRawData()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
+ *
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+ */
+ public static function getAllRawData()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
+ */
+ public static function reload($data)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
+ */
+ private static function getInstalled()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
+ $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+ self::$installed = $installed[count($installed) - 1];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // only require the installed.php file if this file is loaded from its dumped location,
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+ if (substr(__DIR__, -8, 1) !== 'C') {
+ self::$installed = require __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+ $installed[] = self::$installed;
+
+ return $installed;
+ }
+}
diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE
new file mode 100644
index 0000000..f27399a
--- /dev/null
+++ b/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+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/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000..9bb846c
--- /dev/null
+++ b/vendor/composer/autoload_classmap.php
@@ -0,0 +1,11 @@
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+ 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
+);
diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php
new file mode 100644
index 0000000..17e5fff
--- /dev/null
+++ b/vendor/composer/autoload_files.php
@@ -0,0 +1,24 @@
+<?php
+
+// autoload_files.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php',
+ '972fda704d680a3a53c68e34e193cb22' => $vendorDir . '/react/promise-timer/src/functions_include.php',
+ 'ebf8799635f67b5d7248946fe2154f4a' => $vendorDir . '/ringcentral/psr7/src/functions_include.php',
+ 'cea474b4340aa9fa53661e887a21a316' => $vendorDir . '/react/promise-stream/src/functions_include.php',
+ '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
+ 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
+ '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
+ 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
+ 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
+ '45b89995831374eefdfc4161161938f6' => $vendorDir . '/jfcherng/php-color-output/src/helpers.php',
+ '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
+ 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
+ 'f67ee1ef46ff5893b59dcf4c4e98a0e8' => $vendorDir . '/clue/block-react/src/functions_include.php',
+ '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
+ 'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
+);
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
new file mode 100644
index 0000000..ddf739a
--- /dev/null
+++ b/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,12 @@
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'Evenement' => array($vendorDir . '/evenement/evenement/src'),
+ 'Clue\\Redis\\Protocol' => array($vendorDir . '/clue/redis-protocol/src'),
+ 'AssetLoader' => array($baseDir . '/'),
+);
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
new file mode 100644
index 0000000..9959c9a
--- /dev/null
+++ b/vendor/composer/autoload_psr4.php
@@ -0,0 +1,47 @@
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+ 'cweagans\\Composer\\' => array($vendorDir . '/cweagans/composer-patches/src'),
+ 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
+ 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),
+ 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),
+ 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
+ 'Socket\\Raw\\' => array($vendorDir . '/clue/socket-raw/src'),
+ 'RingCentral\\Psr7\\' => array($vendorDir . '/ringcentral/psr7/src'),
+ 'React\\Stream\\' => array($vendorDir . '/react/stream/src'),
+ 'React\\Socket\\' => array($vendorDir . '/react/socket/src'),
+ 'React\\Promise\\Timer\\' => array($vendorDir . '/react/promise-timer/src'),
+ 'React\\Promise\\Stream\\' => array($vendorDir . '/react/promise-stream/src'),
+ 'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
+ 'React\\Http\\' => array($vendorDir . '/react/http/src'),
+ 'React\\HttpClient\\' => array($vendorDir . '/react/http-client/src'),
+ 'React\\EventLoop\\' => array($vendorDir . '/react/event-loop/src'),
+ 'React\\Dns\\' => array($vendorDir . '/react/dns/src'),
+ 'React\\Datagram\\' => array($vendorDir . '/react/datagram/src'),
+ 'React\\ChildProcess\\' => array($vendorDir . '/react/child-process/src'),
+ 'React\\Cache\\' => array($vendorDir . '/react/cache/src'),
+ 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
+ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
+ 'Predis\\' => array($vendorDir . '/predis/predis/src'),
+ 'Jfcherng\\Utility\\' => array($vendorDir . '/jfcherng/php-mb-string/src', $vendorDir . '/jfcherng/php-color-output/src'),
+ 'Jfcherng\\Diff\\' => array($vendorDir . '/jfcherng/php-sequence-matcher/src', $vendorDir . '/jfcherng/php-diff/src'),
+ 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
+ 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
+ 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
+ 'Fig\\Http\\Message\\' => array($vendorDir . '/fig/http-message-util/src'),
+ 'ConnectionManager\\Extra\\' => array($vendorDir . '/clue/connection-manager-extra/src'),
+ 'Clue\\React\\Utf8\\' => array($vendorDir . '/clue/utf8-react/src'),
+ 'Clue\\React\\Term\\' => array($vendorDir . '/clue/term-react/src'),
+ 'Clue\\React\\Stdio\\' => array($vendorDir . '/clue/stdio-react/src'),
+ 'Clue\\React\\Socks\\' => array($vendorDir . '/clue/socks-react/src'),
+ 'Clue\\React\\Soap\\' => array($vendorDir . '/clue/soap-react/src'),
+ 'Clue\\React\\Redis\\' => array($vendorDir . '/clue/redis-react/src'),
+ 'Clue\\React\\Mq\\' => array($vendorDir . '/clue/mq-react/src'),
+ 'Clue\\React\\HttpProxy\\' => array($vendorDir . '/clue/http-proxy-react/src'),
+ 'Clue\\React\\Buzz\\' => array($vendorDir . '/clue/buzz-react/src'),
+);
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
new file mode 100644
index 0000000..5160273
--- /dev/null
+++ b/vendor/composer/autoload_real.php
@@ -0,0 +1,57 @@
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInitd325ec05aa7f058e77e450fa9a6801af
+{
+ private static $loader;
+
+ public static function loadClassLoader($class)
+ {
+ if ('Composer\Autoload\ClassLoader' === $class) {
+ require __DIR__ . '/ClassLoader.php';
+ }
+ }
+
+ /**
+ * @return \Composer\Autoload\ClassLoader
+ */
+ public static function getLoader()
+ {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+
+ require __DIR__ . '/platform_check.php';
+
+ spl_autoload_register(array('ComposerAutoloaderInitd325ec05aa7f058e77e450fa9a6801af', 'loadClassLoader'), true, true);
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
+ spl_autoload_unregister(array('ComposerAutoloaderInitd325ec05aa7f058e77e450fa9a6801af', 'loadClassLoader'));
+
+ require __DIR__ . '/autoload_static.php';
+ call_user_func(\Composer\Autoload\ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::getInitializer($loader));
+
+ $loader->register(true);
+
+ $includeFiles = \Composer\Autoload\ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::$files;
+ foreach ($includeFiles as $fileIdentifier => $file) {
+ composerRequired325ec05aa7f058e77e450fa9a6801af($fileIdentifier, $file);
+ }
+
+ return $loader;
+ }
+}
+
+/**
+ * @param string $fileIdentifier
+ * @param string $file
+ * @return void
+ */
+function composerRequired325ec05aa7f058e77e450fa9a6801af($fileIdentifier, $file)
+{
+ if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+ $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+ require $file;
+ }
+}
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
new file mode 100644
index 0000000..e686941
--- /dev/null
+++ b/vendor/composer/autoload_static.php
@@ -0,0 +1,288 @@
+<?php
+
+// autoload_static.php @generated by Composer
+
+namespace Composer\Autoload;
+
+class ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af
+{
+ public static $files = array (
+ 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
+ '972fda704d680a3a53c68e34e193cb22' => __DIR__ . '/..' . '/react/promise-timer/src/functions_include.php',
+ 'ebf8799635f67b5d7248946fe2154f4a' => __DIR__ . '/..' . '/ringcentral/psr7/src/functions_include.php',
+ 'cea474b4340aa9fa53661e887a21a316' => __DIR__ . '/..' . '/react/promise-stream/src/functions_include.php',
+ '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
+ 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
+ '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
+ 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
+ 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
+ '45b89995831374eefdfc4161161938f6' => __DIR__ . '/..' . '/jfcherng/php-color-output/src/helpers.php',
+ '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
+ 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
+ 'f67ee1ef46ff5893b59dcf4c4e98a0e8' => __DIR__ . '/..' . '/clue/block-react/src/functions_include.php',
+ '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
+ 'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
+ );
+
+ public static $prefixLengthsPsr4 = array (
+ 'c' =>
+ array (
+ 'cweagans\\Composer\\' => 18,
+ ),
+ 'S' =>
+ array (
+ 'Symfony\\Polyfill\\Php72\\' => 23,
+ 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33,
+ 'Symfony\\Polyfill\\Intl\\Idn\\' => 26,
+ 'Symfony\\Polyfill\\Ctype\\' => 23,
+ 'Socket\\Raw\\' => 11,
+ ),
+ 'R' =>
+ array (
+ 'RingCentral\\Psr7\\' => 17,
+ 'React\\Stream\\' => 13,
+ 'React\\Socket\\' => 13,
+ 'React\\Promise\\Timer\\' => 20,
+ 'React\\Promise\\Stream\\' => 21,
+ 'React\\Promise\\' => 14,
+ 'React\\Http\\' => 11,
+ 'React\\HttpClient\\' => 17,
+ 'React\\EventLoop\\' => 16,
+ 'React\\Dns\\' => 10,
+ 'React\\Datagram\\' => 15,
+ 'React\\ChildProcess\\' => 19,
+ 'React\\Cache\\' => 12,
+ 'Ramsey\\Uuid\\' => 12,
+ ),
+ 'P' =>
+ array (
+ 'Psr\\Http\\Message\\' => 17,
+ 'Predis\\' => 7,
+ ),
+ 'J' =>
+ array (
+ 'Jfcherng\\Utility\\' => 17,
+ 'Jfcherng\\Diff\\' => 14,
+ ),
+ 'G' =>
+ array (
+ 'GuzzleHttp\\Psr7\\' => 16,
+ 'GuzzleHttp\\Promise\\' => 19,
+ 'GuzzleHttp\\' => 11,
+ ),
+ 'F' =>
+ array (
+ 'Fig\\Http\\Message\\' => 17,
+ ),
+ 'C' =>
+ array (
+ 'ConnectionManager\\Extra\\' => 24,
+ 'Clue\\React\\Utf8\\' => 16,
+ 'Clue\\React\\Term\\' => 16,
+ 'Clue\\React\\Stdio\\' => 17,
+ 'Clue\\React\\Socks\\' => 17,
+ 'Clue\\React\\Soap\\' => 16,
+ 'Clue\\React\\Redis\\' => 17,
+ 'Clue\\React\\Mq\\' => 14,
+ 'Clue\\React\\HttpProxy\\' => 21,
+ 'Clue\\React\\Buzz\\' => 16,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'cweagans\\Composer\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/cweagans/composer-patches/src',
+ ),
+ 'Symfony\\Polyfill\\Php72\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
+ ),
+ 'Symfony\\Polyfill\\Intl\\Normalizer\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',
+ ),
+ 'Symfony\\Polyfill\\Intl\\Idn\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',
+ ),
+ 'Symfony\\Polyfill\\Ctype\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
+ ),
+ 'Socket\\Raw\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/socket-raw/src',
+ ),
+ 'RingCentral\\Psr7\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/ringcentral/psr7/src',
+ ),
+ 'React\\Stream\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/stream/src',
+ ),
+ 'React\\Socket\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/socket/src',
+ ),
+ 'React\\Promise\\Timer\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/promise-timer/src',
+ ),
+ 'React\\Promise\\Stream\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/promise-stream/src',
+ ),
+ 'React\\Promise\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/promise/src',
+ ),
+ 'React\\Http\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/http/src',
+ ),
+ 'React\\HttpClient\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/http-client/src',
+ ),
+ 'React\\EventLoop\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/event-loop/src',
+ ),
+ 'React\\Dns\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/dns/src',
+ ),
+ 'React\\Datagram\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/datagram/src',
+ ),
+ 'React\\ChildProcess\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/child-process/src',
+ ),
+ 'React\\Cache\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/react/cache/src',
+ ),
+ 'Ramsey\\Uuid\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/ramsey/uuid/src',
+ ),
+ 'Psr\\Http\\Message\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/psr/http-message/src',
+ ),
+ 'Predis\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/predis/predis/src',
+ ),
+ 'Jfcherng\\Utility\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/jfcherng/php-mb-string/src',
+ 1 => __DIR__ . '/..' . '/jfcherng/php-color-output/src',
+ ),
+ 'Jfcherng\\Diff\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/jfcherng/php-sequence-matcher/src',
+ 1 => __DIR__ . '/..' . '/jfcherng/php-diff/src',
+ ),
+ 'GuzzleHttp\\Psr7\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
+ ),
+ 'GuzzleHttp\\Promise\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',
+ ),
+ 'GuzzleHttp\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
+ ),
+ 'Fig\\Http\\Message\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/fig/http-message-util/src',
+ ),
+ 'ConnectionManager\\Extra\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/connection-manager-extra/src',
+ ),
+ 'Clue\\React\\Utf8\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/utf8-react/src',
+ ),
+ 'Clue\\React\\Term\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/term-react/src',
+ ),
+ 'Clue\\React\\Stdio\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/stdio-react/src',
+ ),
+ 'Clue\\React\\Socks\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/socks-react/src',
+ ),
+ 'Clue\\React\\Soap\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/soap-react/src',
+ ),
+ 'Clue\\React\\Redis\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/redis-react/src',
+ ),
+ 'Clue\\React\\Mq\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/mq-react/src',
+ ),
+ 'Clue\\React\\HttpProxy\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/http-proxy-react/src',
+ ),
+ 'Clue\\React\\Buzz\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/buzz-react/src',
+ ),
+ );
+
+ public static $prefixesPsr0 = array (
+ 'E' =>
+ array (
+ 'Evenement' =>
+ array (
+ 0 => __DIR__ . '/..' . '/evenement/evenement/src',
+ ),
+ ),
+ 'C' =>
+ array (
+ 'Clue\\Redis\\Protocol' =>
+ array (
+ 0 => __DIR__ . '/..' . '/clue/redis-protocol/src',
+ ),
+ ),
+ 'A' =>
+ array (
+ 'AssetLoader' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/',
+ ),
+ ),
+ );
+
+ public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::$prefixDirsPsr4;
+ $loader->prefixesPsr0 = ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::$prefixesPsr0;
+ $loader->classMap = ComposerStaticInitd325ec05aa7f058e77e450fa9a6801af::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
new file mode 100644
index 0000000..08236e9
--- /dev/null
+++ b/vendor/composer/installed.json
@@ -0,0 +1,3433 @@
+{
+ "packages": [
+ {
+ "name": "clue/block-react",
+ "version": "v1.5.0",
+ "version_normalized": "1.5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-block.git",
+ "reference": "718b0571a94aa693c6fffc72182e87257ac900f3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-block/zipball/718b0571a94aa693c6fffc72182e87257ac900f3",
+ "reference": "718b0571a94aa693c6fffc72182e87257ac900f3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/http": "^1.4"
+ },
+ "time": "2021-10-20T14:07:33+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Lightweight library that eases integrating async components built for ReactPHP in a traditional, blocking environment.",
+ "homepage": "https://github.com/clue/reactphp-block",
+ "keywords": [
+ "async",
+ "await",
+ "blocking",
+ "event loop",
+ "promise",
+ "reactphp",
+ "sleep",
+ "synchronous"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-block/issues",
+ "source": "https://github.com/clue/reactphp-block/tree/v1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/block-react"
+ },
+ {
+ "name": "clue/buzz-react",
+ "version": "v2.9.0",
+ "version_normalized": "2.9.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-buzz.git",
+ "reference": "eb180b5e0db00a3febaa458289706b8ca80ffe2a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-buzz/zipball/eb180b5e0db00a3febaa458289706b8ca80ffe2a",
+ "reference": "eb180b5e0db00a3febaa458289706b8ca80ffe2a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/http-client": "^0.5.10",
+ "react/promise": "^2.2.1 || ^1.2.1",
+ "react/promise-stream": "^1.0 || ^0.1.2",
+ "react/socket": "^1.1",
+ "react/stream": "^1.0 || ^0.7",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "clue/http-proxy-react": "^1.3",
+ "clue/reactphp-ssh-proxy": "^1.0",
+ "clue/socks-react": "^1.0",
+ "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35",
+ "react/http": "^0.8"
+ },
+ "time": "2020-07-03T10:43:43+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Buzz\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Simple, async PSR-7 HTTP client for concurrently processing any number of HTTP requests, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-buzz",
+ "keywords": [
+ "async",
+ "http",
+ "http client",
+ "psr-7",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-buzz/issues",
+ "source": "https://github.com/clue/reactphp-buzz/tree/v2.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "abandoned": "react/http",
+ "install-path": "../clue/buzz-react"
+ },
+ {
+ "name": "clue/connection-manager-extra",
+ "version": "v1.2.0",
+ "version_normalized": "1.2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-connection-manager-extra.git",
+ "reference": "95e7033af27a74a793b30dc9f049fbaf93de2c2c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-connection-manager-extra/zipball/95e7033af27a74a793b30dc9f049fbaf93de2c2c",
+ "reference": "95e7033af27a74a793b30dc9f049fbaf93de2c2c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/promise-timer": "^1.1",
+ "react/socket": "^1.0 || ^0.8 || ^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8"
+ },
+ "time": "2020-12-12T15:42:48+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "ConnectionManager\\Extra\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Extra decorators for creating async TCP/IP connections, built on top of ReactPHP's Socket component",
+ "homepage": "https://github.com/clue/reactphp-connection-manager-extra",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "acl",
+ "delay",
+ "firewall",
+ "network",
+ "random",
+ "reactphp",
+ "reject",
+ "repeat",
+ "retry",
+ "timeout"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-connection-manager-extra/issues",
+ "source": "https://github.com/clue/reactphp-connection-manager-extra/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/connection-manager-extra"
+ },
+ {
+ "name": "clue/http-proxy-react",
+ "version": "v1.7.0",
+ "version_normalized": "1.7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-http-proxy.git",
+ "reference": "8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8",
+ "reference": "8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": " ^2.1 || ^1.2.1",
+ "react/socket": "^1.9",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "time": "2021-08-06T13:05:41+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\HttpProxy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-http-proxy",
+ "keywords": [
+ "async",
+ "connect",
+ "http",
+ "proxy",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-http-proxy/issues",
+ "source": "https://github.com/clue/reactphp-http-proxy/tree/v1.7.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/http-proxy-react"
+ },
+ {
+ "name": "clue/mq-react",
+ "version": "v1.4.0",
+ "version_normalized": "1.4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-mq.git",
+ "reference": "3f2ea2c2947522022ba5ff6c52267fa3f2c0f193"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-mq/zipball/3f2ea2c2947522022ba5ff6c52267fa3f2c0f193",
+ "reference": "3f2ea2c2947522022ba5ff6c52267fa3f2c0f193",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.2.1 || ^1.2.1"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "time": "2021-11-15T10:50:53+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Mq\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-mq",
+ "keywords": [
+ "Mini Queue",
+ "async",
+ "concurrency",
+ "job",
+ "message",
+ "message queue",
+ "queue",
+ "rate limit",
+ "reactphp",
+ "throttle",
+ "worker"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-mq/issues",
+ "source": "https://github.com/clue/reactphp-mq/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/mq-react"
+ },
+ {
+ "name": "clue/redis-protocol",
+ "version": "v0.3.1",
+ "version_normalized": "0.3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/php-redis-protocol.git",
+ "reference": "271b8009887209d930f613ad3b9518f94bd6b51c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/php-redis-protocol/zipball/271b8009887209d930f613ad3b9518f94bd6b51c",
+ "reference": "271b8009887209d930f613ad3b9518f94bd6b51c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "time": "2017-06-06T16:07:10+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Clue\\Redis\\Protocol": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "keywords": [
+ "parser",
+ "protocol",
+ "redis",
+ "serializer",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/php-redis-protocol/issues",
+ "source": "https://github.com/clue/php-redis-protocol/tree/v0.3.1"
+ },
+ "install-path": "../clue/redis-protocol"
+ },
+ {
+ "name": "clue/redis-react",
+ "version": "v2.6.0",
+ "version_normalized": "2.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-redis.git",
+ "reference": "f911455f9d7a77dd6f39c22548ddff521544b291"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/f911455f9d7a77dd6f39c22548ddff521544b291",
+ "reference": "f911455f9d7a77dd6f39c22548ddff521544b291",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-protocol": "0.3.*",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.0 || ^1.1",
+ "react/promise-timer": "^1.8",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2022-05-09T09:50:02+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Redis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async Redis client implementation, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-redis",
+ "keywords": [
+ "async",
+ "client",
+ "database",
+ "reactphp",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-redis/issues",
+ "source": "https://github.com/clue/reactphp-redis/tree/v2.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/redis-react"
+ },
+ {
+ "name": "clue/soap-react",
+ "version": "v1.0.0",
+ "version_normalized": "1.0.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-soap.git",
+ "reference": "72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-soap/zipball/72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393",
+ "reference": "72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393",
+ "shasum": ""
+ },
+ "require": {
+ "clue/buzz-react": "^2.5",
+ "ext-soap": "*",
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35"
+ },
+ "time": "2018-11-07T17:19:24+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Soap\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "Simple, async SOAP webservice client library, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-soap",
+ "keywords": [
+ "reactphp",
+ "soap",
+ "soapclient",
+ "webservice",
+ "wsdl"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-soap/issues",
+ "source": "https://github.com/clue/reactphp-soap/tree/v1.0.0"
+ },
+ "install-path": "../clue/soap-react"
+ },
+ {
+ "name": "clue/socket-raw",
+ "version": "v1.6.0",
+ "version_normalized": "1.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/socket-raw.git",
+ "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/socket-raw/zipball/91e9f619f6769f931454a9882c21ffd7623d06cb",
+ "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-sockets": "*",
+ "php": ">=5.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2022-04-14T14:58:06+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Socket\\Raw\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets).",
+ "homepage": "https://github.com/clue/socket-raw",
+ "keywords": [
+ "Socket",
+ "client",
+ "datagram",
+ "dgram",
+ "icmp",
+ "ipv6",
+ "server",
+ "stream",
+ "tcp",
+ "udg",
+ "udp",
+ "unix"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/socket-raw/issues",
+ "source": "https://github.com/clue/socket-raw/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/socket-raw"
+ },
+ {
+ "name": "clue/socks-react",
+ "version": "v1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-socks.git",
+ "reference": "f90edf489313301e87292c51d41faf8c21138513"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-socks/zipball/f90edf489313301e87292c51d41faf8c21138513",
+ "reference": "f90edf489313301e87292c51d41faf8c21138513",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/socket": "^1.9"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "clue/connection-manager-extra": "^1.0 || ^0.7",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.2",
+ "react/http": "^1.5"
+ },
+ "time": "2021-08-06T13:06:59+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Socks\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async SOCKS proxy connector client and server implementation, tunnel any TCP/IP-based protocol through a SOCKS5 or SOCKS4(a) proxy server, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-socks",
+ "keywords": [
+ "async",
+ "proxy server",
+ "reactphp",
+ "socks client",
+ "socks server",
+ "socks4a",
+ "socks5",
+ "tcp tunnel"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-socks/issues",
+ "source": "https://github.com/clue/reactphp-socks/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/socks-react"
+ },
+ {
+ "name": "clue/stdio-react",
+ "version": "v2.6.0",
+ "version_normalized": "2.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-stdio.git",
+ "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-stdio/zipball/dfa6c378aabdff718202d4e2453f752c38ea3399",
+ "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399",
+ "shasum": ""
+ },
+ "require": {
+ "clue/term-react": "^1.0 || ^0.1.1",
+ "clue/utf8-react": "^1.0 || ^0.1",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/arguments": "^2.0",
+ "clue/commander": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
+ },
+ "time": "2022-03-18T15:09:30+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Stdio\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async, event-driven console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP",
+ "homepage": "https://github.com/clue/reactphp-stdio",
+ "keywords": [
+ "async",
+ "autocomplete",
+ "autocompletion",
+ "cli",
+ "history",
+ "interactive",
+ "reactphp",
+ "readline",
+ "stdin",
+ "stdio",
+ "stdout"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-stdio/issues",
+ "source": "https://github.com/clue/reactphp-stdio/tree/v2.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/stdio-react"
+ },
+ {
+ "name": "clue/term-react",
+ "version": "v1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-term.git",
+ "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-term/zipball/eb6eb063eda04a714ef89f066586a2c49588f7ca",
+ "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3"
+ },
+ "time": "2020-11-06T11:50:12+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Term\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming terminal emulator, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-term",
+ "keywords": [
+ "C0",
+ "CSI",
+ "ansi",
+ "apc",
+ "ascii",
+ "c1",
+ "control codes",
+ "dps",
+ "osc",
+ "pm",
+ "reactphp",
+ "streaming",
+ "terminal",
+ "vt100",
+ "xterm"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-term/issues",
+ "source": "https://github.com/clue/reactphp-term/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/term-react"
+ },
+ {
+ "name": "clue/utf8-react",
+ "version": "v1.2.0",
+ "version_normalized": "1.2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-utf8.git",
+ "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-utf8/zipball/8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
+ "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4 || ^0.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 ||^5.7 || ^4.8",
+ "react/stream": "^1.0 || ^0.7"
+ },
+ "time": "2020-11-06T11:48:09+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Utf8\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Streaming UTF-8 parser, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-utf8",
+ "keywords": [
+ "reactphp",
+ "streaming",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-utf8/issues",
+ "source": "https://github.com/clue/reactphp-utf8/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../clue/utf8-react"
+ },
+ {
+ "name": "components/jquery",
+ "version": "3.6.0",
+ "version_normalized": "3.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/components/jquery.git",
+ "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/components/jquery/zipball/6cf38ee1fd04b6adf8e7dda161283aa35be818c3",
+ "reference": "6cf38ee1fd04b6adf8e7dda161283aa35be818c3",
+ "shasum": ""
+ },
+ "time": "2021-03-20T19:13:42+00:00",
+ "type": "component",
+ "extra": {
+ "component": {
+ "scripts": [
+ "jquery.js"
+ ],
+ "files": [
+ "jquery.min.js",
+ "jquery.min.map",
+ "jquery.slim.js",
+ "jquery.slim.min.js",
+ "jquery.slim.min.map"
+ ]
+ }
+ },
+ "installation-source": "dist",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "JS Foundation and other contributors"
+ }
+ ],
+ "description": "jQuery JavaScript Library",
+ "homepage": "http://jquery.com",
+ "support": {
+ "forum": "http://forum.jquery.com",
+ "irc": "irc://irc.freenode.org/jquery",
+ "issues": "https://github.com/jquery/jquery/issues",
+ "source": "https://github.com/jquery/jquery",
+ "wiki": "http://docs.jquery.com/"
+ },
+ "install-path": "../components/jquery"
+ },
+ {
+ "name": "cweagans/composer-patches",
+ "version": "1.7.2",
+ "version_normalized": "1.7.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cweagans/composer-patches.git",
+ "reference": "e9969cfc0796e6dea9b4e52f77f18e1065212871"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e9969cfc0796e6dea9b4e52f77f18e1065212871",
+ "reference": "e9969cfc0796e6dea9b4e52f77f18e1065212871",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0 || ^2.0",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "composer/composer": "~1.0 || ~2.0",
+ "phpunit/phpunit": "~4.6"
+ },
+ "time": "2022-01-25T19:21:20+00:00",
+ "type": "composer-plugin",
+ "extra": {
+ "class": "cweagans\\Composer\\Patches"
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "cweagans\\Composer\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Cameron Eagans",
+ "email": "me@cweagans.net"
+ }
+ ],
+ "description": "Provides a way to patch Composer packages.",
+ "support": {
+ "issues": "https://github.com/cweagans/composer-patches/issues",
+ "source": "https://github.com/cweagans/composer-patches/tree/1.7.2"
+ },
+ "install-path": "../cweagans/composer-patches"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.1",
+ "version_normalized": "3.0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
+ "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "time": "2017-07-23T21:35:13+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Evenement": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/master"
+ },
+ "install-path": "../evenement/evenement"
+ },
+ {
+ "name": "fig/http-message-util",
+ "version": "1.1.5",
+ "version_normalized": "1.1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message-util.git",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3 || ^7.0 || ^8.0"
+ },
+ "suggest": {
+ "psr/http-message": "The package containing the PSR-7 interfaces"
+ },
+ "time": "2020-11-24T22:02:12+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Fig\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/http-message-util/issues",
+ "source": "https://github.com/php-fig/http-message-util/tree/1.1.5"
+ },
+ "install-path": "../fig/http-message-util"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.5.7",
+ "version_normalized": "6.5.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "724562fa861e21a4071c652c8a159934e4f05592"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/724562fa861e21a4071c652c8a159934e4f05592",
+ "reference": "724562fa861e21a4071c652c8a159934e4f05592",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1",
+ "php": ">=5.5",
+ "symfony/polyfill-intl-idn": "^1.17.0"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "time": "2022-06-09T21:36:50+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.5-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/6.5.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../guzzlehttp/guzzle"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "1.5.1",
+ "version_normalized": "1.5.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
+ "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ },
+ "time": "2021-10-22T20:56:57+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.5-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/1.5.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../guzzlehttp/promises"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.8.5",
+ "version_normalized": "1.8.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/337e3ad8e5716c15f9657bd214d16cc5e69df268",
+ "reference": "337e3ad8e5716c15f9657bd214d16cc5e69df268",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "ext-zlib": "*",
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
+ },
+ "suggest": {
+ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "time": "2022-03-20T21:51:18+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.7-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/psr7/issues",
+ "source": "https://github.com/guzzle/psr7/tree/1.8.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../guzzlehttp/psr7"
+ },
+ {
+ "name": "jfcherng/php-color-output",
+ "version": "2.0.2",
+ "version_normalized": "2.0.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-color-output.git",
+ "reference": "2673074597eca9682d2fdfaee39a22418d4cc2f6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-color-output/zipball/2673074597eca9682d2fdfaee39a22418d4cc2f6",
+ "reference": "2673074597eca9682d2fdfaee39a22418d4cc2f6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.15",
+ "phan/phan": "^2.2",
+ "phpunit/phpunit": "^7.2 || ^8.2 || ^9",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "time": "2020-05-27T19:24:44+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/helpers.php"
+ ],
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "Make your PHP command-line application colorful.",
+ "keywords": [
+ "ansi-colors",
+ "color",
+ "command-line",
+ "str-color"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-color-output/issues",
+ "source": "https://github.com/jfcherng/php-color-output/tree/2.0.2"
+ },
+ "install-path": "../jfcherng/php-color-output"
+ },
+ {
+ "name": "jfcherng/php-diff",
+ "version": "6.10.4",
+ "version_normalized": "6.10.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-diff.git",
+ "reference": "ccc178b81ac737b0f9a60e7210d26d5ed797e786"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-diff/zipball/ccc178b81ac737b0f9a60e7210d26d5ed797e786",
+ "reference": "ccc178b81ac737b0f9a60e7210d26d5ed797e786",
+ "shasum": ""
+ },
+ "require": {
+ "jfcherng/php-color-output": "^2.0",
+ "jfcherng/php-mb-string": "^1.4.6",
+ "jfcherng/php-sequence-matcher": "^3.2.8",
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.6"
+ },
+ "time": "2022-04-02T16:36:51+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A comprehensive library for generating differences between two strings in multiple formats (unified, side by side HTML etc).",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/jfcherng/php-diff/issues",
+ "source": "https://github.com/jfcherng/php-diff/tree/6.10.4"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "install-path": "../jfcherng/php-diff"
+ },
+ {
+ "name": "jfcherng/php-mb-string",
+ "version": "1.4.6",
+ "version_normalized": "1.4.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-mb-string.git",
+ "reference": "f5b438d348e030961e0b86a04ef2319c31ae8146"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-mb-string/zipball/f5b438d348e030961e0b86a04ef2319c31ae8146",
+ "reference": "f5b438d348e030961e0b86a04ef2319c31ae8146",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.18",
+ "phan/phan": "^2 || ^3 || ^4",
+ "phpunit/phpunit": "^7.2 || ^8 || ^9"
+ },
+ "time": "2022-04-02T16:32:41+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "description": "A high performance multibytes sting implementation for frequently reading/writing operations.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-mb-string/issues",
+ "source": "https://github.com/jfcherng/php-mb-string/tree/1.4.6"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "install-path": "../jfcherng/php-mb-string"
+ },
+ {
+ "name": "jfcherng/php-sequence-matcher",
+ "version": "3.2.8",
+ "version_normalized": "3.2.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jfcherng/php-sequence-matcher.git",
+ "reference": "410519ca07cd7989f450d6e2aa40975dbd1be048"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jfcherng/php-sequence-matcher/zipball/410519ca07cd7989f450d6e2aa40975dbd1be048",
+ "reference": "410519ca07cd7989f450d6e2aa40975dbd1be048",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4 || ^5",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "time": "2021-09-02T04:02:02+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "description": "A longest sequence matcher. The logic is primarily based on the Python difflib package.",
+ "support": {
+ "issues": "https://github.com/jfcherng/php-sequence-matcher/issues",
+ "source": "https://github.com/jfcherng/php-sequence-matcher/tree/3.2.8"
+ },
+ "funding": [
+ {
+ "url": "https://www.paypal.me/jfcherng/5usd",
+ "type": "custom"
+ }
+ ],
+ "install-path": "../jfcherng/php-sequence-matcher"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "version_normalized": "9.99.100.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "time": "2020-10-15T08:29:30+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "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",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "install-path": "../paragonie/random_compat"
+ },
+ {
+ "name": "predis/predis",
+ "version": "v1.1.10",
+ "version_normalized": "1.1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/predis/predis.git",
+ "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/predis/predis/zipball/a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e",
+ "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "suggest": {
+ "ext-curl": "Allows access to Webdis when paired with phpiredis",
+ "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
+ },
+ "time": "2022-01-05T17:46:08+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Predis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniele Alessandri",
+ "email": "suppakilla@gmail.com",
+ "homepage": "http://clorophilla.net",
+ "role": "Creator & Maintainer"
+ },
+ {
+ "name": "Till Krüss",
+ "homepage": "https://till.im",
+ "role": "Maintainer"
+ }
+ ],
+ "description": "Flexible and feature-complete Redis client for PHP and HHVM",
+ "homepage": "http://github.com/predis/predis",
+ "keywords": [
+ "nosql",
+ "predis",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/predis/predis/issues",
+ "source": "https://github.com/predis/predis/tree/v1.1.10"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/tillkruss",
+ "type": "github"
+ }
+ ],
+ "install-path": "../predis/predis"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "version_normalized": "1.0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "time": "2016-08-06T14:39:51+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/master"
+ },
+ "install-path": "../psr/http-message"
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "version_normalized": "3.0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "time": "2019-03-08T08:55:37+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "support": {
+ "issues": "https://github.com/ralouphie/getallheaders/issues",
+ "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+ },
+ "install-path": "../ralouphie/getallheaders"
+ },
+ {
+ "name": "ramsey/uuid",
+ "version": "3.9.6",
+ "version_normalized": "3.9.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/uuid.git",
+ "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
+ "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
+ "php": "^5.4 | ^7.0 | ^8.0",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "replace": {
+ "rhumsaa/uuid": "self.version"
+ },
+ "require-dev": {
+ "codeception/aspect-mock": "^1 | ^2",
+ "doctrine/annotations": "^1.2",
+ "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
+ "mockery/mockery": "^0.9.11 | ^1",
+ "moontoast/math": "^1.1",
+ "nikic/php-parser": "<=4.5.0",
+ "paragonie/random-lib": "^2",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+ "squizlabs/php_codesniffer": "^3.5",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "suggest": {
+ "ext-ctype": "Provides support for PHP Ctype functions",
+ "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+ "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+ "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+ "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+ "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+ "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+ "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+ },
+ "time": "2021-09-25T23:07:42+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ },
+ "patches_applied": {
+ "Uuid: Add PHP 8.1 support": "patches/ramsey-uuid.patch"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ },
+ {
+ "name": "Marijn Huizendveld",
+ "email": "marijn.huizendveld@gmail.com"
+ },
+ {
+ "name": "Thibaud Fabre",
+ "email": "thibaud@aztech.io"
+ }
+ ],
+ "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+ "homepage": "https://github.com/ramsey/uuid",
+ "keywords": [
+ "guid",
+ "identifier",
+ "uuid"
+ ],
+ "support": {
+ "issues": "https://github.com/ramsey/uuid/issues",
+ "rss": "https://github.com/ramsey/uuid/releases.atom",
+ "source": "https://github.com/ramsey/uuid",
+ "wiki": "https://github.com/ramsey/uuid/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ramsey",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../ramsey/uuid"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.1.1",
+ "version_normalized": "1.1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/4bf736a2cccec7298bdf745db77585966fc2ca7e",
+ "reference": "4bf736a2cccec7298bdf745db77585966fc2ca7e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2021-02-02T06:47:52+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/cache"
+ },
+ {
+ "name": "react/child-process",
+ "version": "v0.6.4",
+ "version_normalized": "0.6.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/a778f3fb828d68caf8a9ab6567fd8342a86f12fe",
+ "reference": "a778f3fb828d68caf8a9ab6567fd8342a86f12fe",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/socket": "^1.8",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
+ },
+ "time": "2021-10-12T10:37:07+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\ChildProcess\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven library for executing child processes with ReactPHP.",
+ "keywords": [
+ "event-driven",
+ "process",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/child-process/issues",
+ "source": "https://github.com/reactphp/child-process/tree/v0.6.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/child-process"
+ },
+ {
+ "name": "react/datagram",
+ "version": "v1.8.0",
+ "version_normalized": "1.8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/datagram.git",
+ "reference": "40f2c39f83541367018605a73b57c99186f7145c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/datagram/zipball/40f2c39f83541367018605a73b57c99186f7145c",
+ "reference": "40f2c39f83541367018605a73b57c99186f7145c",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/dns": "^1.7",
+ "react/event-loop": "^1.2",
+ "react/promise": "~2.1|~1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "~1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2021-07-11T13:06:40+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Datagram\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven UDP datagram socket client and server for ReactPHP",
+ "homepage": "https://github.com/reactphp/datagram",
+ "keywords": [
+ "Socket",
+ "async",
+ "client",
+ "datagram",
+ "dgram",
+ "reactphp",
+ "server",
+ "udp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/datagram/issues",
+ "source": "https://github.com/reactphp/datagram/tree/v1.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/datagram"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.9.0",
+ "version_normalized": "1.9.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb",
+ "reference": "6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.8"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^4.8.35"
+ },
+ "time": "2021-12-20T08:46:54+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/dns"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/187fb56f46d424afb6ec4ad089269c72eec2e137",
+ "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-event": "~1.0 for ExtEventLoop",
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop",
+ "ext-uv": "* for ExtUvLoop"
+ },
+ "time": "2022-03-17T11:10:22+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/event-loop"
+ },
+ {
+ "name": "react/http",
+ "version": "v1.6.0",
+ "version_normalized": "1.6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/http.git",
+ "reference": "59961cc4a5b14481728f07c591546be18fa3a5c7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/http/zipball/59961cc4a5b14481728f07c591546be18fa3a5c7",
+ "reference": "59961cc4a5b14481728f07c591546be18fa3a5c7",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "fig/http-message-util": "^1.1",
+ "php": ">=5.3.0",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.3 || ^1.2.1",
+ "react/promise-stream": "^1.1",
+ "react/socket": "^1.9",
+ "react/stream": "^1.2",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "clue/http-proxy-react": "^1.7",
+ "clue/reactphp-ssh-proxy": "^1.3",
+ "clue/socks-react": "^1.3",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2022-02-03T13:17:37+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Http\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven, streaming HTTP client and server implementation for ReactPHP",
+ "keywords": [
+ "async",
+ "client",
+ "event-driven",
+ "http",
+ "http client",
+ "http server",
+ "https",
+ "psr-7",
+ "reactphp",
+ "server",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/http/issues",
+ "source": "https://github.com/reactphp/http/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/http"
+ },
+ {
+ "name": "react/http-client",
+ "version": "v0.5.11",
+ "version_normalized": "0.5.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/http-client.git",
+ "reference": "23dddb415b9bd36c81d1c78df63143e65702aa4b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/http-client/zipball/23dddb415b9bd36c81d1c78df63143e65702aa4b",
+ "reference": "23dddb415b9bd36c81d1c78df63143e65702aa4b",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/socket": "^1.0 || ^0.8.4",
+ "react/stream": "^1.0 || ^0.7.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.1"
+ },
+ "time": "2021-04-07T16:49:17+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\HttpClient\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Event-driven, streaming HTTP client for ReactPHP",
+ "keywords": [
+ "http"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/http-client/issues",
+ "source": "https://github.com/reactphp/http-client/tree/v0.5.11"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "abandoned": "react/http",
+ "install-path": "../react/http-client"
+ },
+ {
+ "name": "react/promise",
+ "version": "v2.9.0",
+ "version_normalized": "2.9.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
+ },
+ "time": "2022-02-11T10:27:51+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v2.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/promise"
+ },
+ {
+ "name": "react/promise-stream",
+ "version": "v1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-stream.git",
+ "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/3ebd94fe0d8edbf44937948af28d02d5437e9949",
+ "reference": "3ebd94fe0d8edbf44937948af28d02d5437e9949",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise-timer": "^1.0"
+ },
+ "time": "2021-10-18T10:47:09+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "The missing link between Promise-land and Stream-land for ReactPHP",
+ "homepage": "https://github.com/reactphp/promise-stream",
+ "keywords": [
+ "Buffer",
+ "async",
+ "promise",
+ "reactphp",
+ "stream",
+ "unwrap"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-stream/issues",
+ "source": "https://github.com/reactphp/promise-stream/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/promise-stream"
+ },
+ {
+ "name": "react/promise-timer",
+ "version": "v1.9.0",
+ "version_normalized": "1.9.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-timer.git",
+ "reference": "aa7a73c74b8d8c0f622f5982ff7b0351bc29e495"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/aa7a73c74b8d8c0f622f5982ff7b0351bc29e495",
+ "reference": "aa7a73c74b8d8c0f622f5982ff7b0351bc29e495",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2022-06-13T13:41:03+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Timer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+ "homepage": "https://github.com/reactphp/promise-timer",
+ "keywords": [
+ "async",
+ "event-loop",
+ "promise",
+ "reactphp",
+ "timeout",
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-timer/issues",
+ "source": "https://github.com/reactphp/promise-timer/tree/v1.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/promise-timer"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.11.0",
+ "version_normalized": "1.11.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/f474156aaab4f09041144fa8b57c7d70aed32a1c",
+ "reference": "f474156aaab4f09041144fa8b57c7d70aed32a1c",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.8",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.6.0 || ^1.2.1",
+ "react/promise-timer": "^1.8",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.2"
+ },
+ "time": "2022-01-14T10:14:32+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.11.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/socket"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.2.0",
+ "version_normalized": "1.2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
+ "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "time": "2021-07-11T12:37:55+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "install-path": "../react/stream"
+ },
+ {
+ "name": "ringcentral/psr7",
+ "version": "1.3.0",
+ "version_normalized": "1.3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ringcentral/psr7.git",
+ "reference": "360faaec4b563958b673fb52bbe94e37f14bc686"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ringcentral/psr7/zipball/360faaec4b563958b673fb52bbe94e37f14bc686",
+ "reference": "360faaec4b563958b673fb52bbe94e37f14bc686",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "~1.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "time": "2018-05-29T20:21:04+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "RingCentral\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "PSR-7 message implementation",
+ "keywords": [
+ "http",
+ "message",
+ "stream",
+ "uri"
+ ],
+ "support": {
+ "source": "https://github.com/ringcentral/psr7/tree/master"
+ },
+ "install-path": "../ringcentral/psr7"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.26.0",
+ "version_normalized": "1.26.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+ "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "time": "2022-05-24T11:49:31+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/polyfill-ctype"
+ },
+ {
+ "name": "symfony/polyfill-intl-idn",
+ "version": "v1.26.0",
+ "version_normalized": "1.26.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-idn.git",
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
+ "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1",
+ "symfony/polyfill-intl-normalizer": "^1.10",
+ "symfony/polyfill-php72": "^1.10"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "time": "2022-05-24T11:49:31+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Idn\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Laurent Bassin",
+ "email": "laurent@bassin.info"
+ },
+ {
+ "name": "Trevor Rowbotham",
+ "email": "trevor.rowbotham@pm.me"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "idn",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/polyfill-intl-idn"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.26.0",
+ "version_normalized": "1.26.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
+ "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "time": "2022-05-24T11:49:31+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "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 intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/polyfill-intl-normalizer"
+ },
+ {
+ "name": "symfony/polyfill-php72",
+ "version": "v1.26.0",
+ "version_normalized": "1.26.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php72.git",
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2",
+ "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "time": "2022-05-24T11:49:31+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php72\\": ""
+ }
+ },
+ "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 backporting some PHP 7.2+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "install-path": "../symfony/polyfill-php72"
+ }
+ ],
+ "dev": true,
+ "dev-package-names": []
+}
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
new file mode 100644
index 0000000..0480c0b
--- /dev/null
+++ b/vendor/composer/installed.php
@@ -0,0 +1,449 @@
+<?php return array(
+ 'root' => array(
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'type' => 'project',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'reference' => '2b056ffa5b22c875d59d33572e4bdaa529de53c5',
+ 'name' => 'icinga/icinga-php-thirdparty',
+ 'dev' => true,
+ ),
+ 'versions' => array(
+ 'clue/block-react' => array(
+ 'pretty_version' => 'v1.5.0',
+ 'version' => '1.5.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/block-react',
+ 'aliases' => array(),
+ 'reference' => '718b0571a94aa693c6fffc72182e87257ac900f3',
+ 'dev_requirement' => false,
+ ),
+ 'clue/buzz-react' => array(
+ 'pretty_version' => 'v2.9.0',
+ 'version' => '2.9.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/buzz-react',
+ 'aliases' => array(),
+ 'reference' => 'eb180b5e0db00a3febaa458289706b8ca80ffe2a',
+ 'dev_requirement' => false,
+ ),
+ 'clue/connection-manager-extra' => array(
+ 'pretty_version' => 'v1.2.0',
+ 'version' => '1.2.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/connection-manager-extra',
+ 'aliases' => array(),
+ 'reference' => '95e7033af27a74a793b30dc9f049fbaf93de2c2c',
+ 'dev_requirement' => false,
+ ),
+ 'clue/http-proxy-react' => array(
+ 'pretty_version' => 'v1.7.0',
+ 'version' => '1.7.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/http-proxy-react',
+ 'aliases' => array(),
+ 'reference' => '8b2f18cd7bc8b2fb383ac24294d28f340a8cfcb8',
+ 'dev_requirement' => false,
+ ),
+ 'clue/mq-react' => array(
+ 'pretty_version' => 'v1.4.0',
+ 'version' => '1.4.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/mq-react',
+ 'aliases' => array(),
+ 'reference' => '3f2ea2c2947522022ba5ff6c52267fa3f2c0f193',
+ 'dev_requirement' => false,
+ ),
+ 'clue/redis-protocol' => array(
+ 'pretty_version' => 'v0.3.1',
+ 'version' => '0.3.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/redis-protocol',
+ 'aliases' => array(),
+ 'reference' => '271b8009887209d930f613ad3b9518f94bd6b51c',
+ 'dev_requirement' => false,
+ ),
+ 'clue/redis-react' => array(
+ 'pretty_version' => 'v2.6.0',
+ 'version' => '2.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/redis-react',
+ 'aliases' => array(),
+ 'reference' => 'f911455f9d7a77dd6f39c22548ddff521544b291',
+ 'dev_requirement' => false,
+ ),
+ 'clue/soap-react' => array(
+ 'pretty_version' => 'v1.0.0',
+ 'version' => '1.0.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/soap-react',
+ 'aliases' => array(),
+ 'reference' => '72ec7d5a67ccfbfbc80cc349145c8b14f4a7f393',
+ 'dev_requirement' => false,
+ ),
+ 'clue/socket-raw' => array(
+ 'pretty_version' => 'v1.6.0',
+ 'version' => '1.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/socket-raw',
+ 'aliases' => array(),
+ 'reference' => '91e9f619f6769f931454a9882c21ffd7623d06cb',
+ 'dev_requirement' => false,
+ ),
+ 'clue/socks-react' => array(
+ 'pretty_version' => 'v1.3.0',
+ 'version' => '1.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/socks-react',
+ 'aliases' => array(),
+ 'reference' => 'f90edf489313301e87292c51d41faf8c21138513',
+ 'dev_requirement' => false,
+ ),
+ 'clue/stdio-react' => array(
+ 'pretty_version' => 'v2.6.0',
+ 'version' => '2.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/stdio-react',
+ 'aliases' => array(),
+ 'reference' => 'dfa6c378aabdff718202d4e2453f752c38ea3399',
+ 'dev_requirement' => false,
+ ),
+ 'clue/term-react' => array(
+ 'pretty_version' => 'v1.3.0',
+ 'version' => '1.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/term-react',
+ 'aliases' => array(),
+ 'reference' => 'eb6eb063eda04a714ef89f066586a2c49588f7ca',
+ 'dev_requirement' => false,
+ ),
+ 'clue/utf8-react' => array(
+ 'pretty_version' => 'v1.2.0',
+ 'version' => '1.2.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../clue/utf8-react',
+ 'aliases' => array(),
+ 'reference' => '8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96',
+ 'dev_requirement' => false,
+ ),
+ 'components/jquery' => array(
+ 'pretty_version' => '3.6.0',
+ 'version' => '3.6.0.0',
+ 'type' => 'component',
+ 'install_path' => __DIR__ . '/../components/jquery',
+ 'aliases' => array(),
+ 'reference' => '6cf38ee1fd04b6adf8e7dda161283aa35be818c3',
+ 'dev_requirement' => false,
+ ),
+ 'cweagans/composer-patches' => array(
+ 'pretty_version' => '1.7.2',
+ 'version' => '1.7.2.0',
+ 'type' => 'composer-plugin',
+ 'install_path' => __DIR__ . '/../cweagans/composer-patches',
+ 'aliases' => array(),
+ 'reference' => 'e9969cfc0796e6dea9b4e52f77f18e1065212871',
+ 'dev_requirement' => false,
+ ),
+ 'evenement/evenement' => array(
+ 'pretty_version' => 'v3.0.1',
+ 'version' => '3.0.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../evenement/evenement',
+ 'aliases' => array(),
+ 'reference' => '531bfb9d15f8aa57454f5f0285b18bec903b8fb7',
+ 'dev_requirement' => false,
+ ),
+ 'fig/http-message-util' => array(
+ 'pretty_version' => '1.1.5',
+ 'version' => '1.1.5.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../fig/http-message-util',
+ 'aliases' => array(),
+ 'reference' => '9d94dc0154230ac39e5bf89398b324a86f63f765',
+ 'dev_requirement' => false,
+ ),
+ 'guzzlehttp/guzzle' => array(
+ 'pretty_version' => '6.5.7',
+ 'version' => '6.5.7.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
+ 'aliases' => array(),
+ 'reference' => '724562fa861e21a4071c652c8a159934e4f05592',
+ 'dev_requirement' => false,
+ ),
+ 'guzzlehttp/promises' => array(
+ 'pretty_version' => '1.5.1',
+ 'version' => '1.5.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../guzzlehttp/promises',
+ 'aliases' => array(),
+ 'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
+ 'dev_requirement' => false,
+ ),
+ 'guzzlehttp/psr7' => array(
+ 'pretty_version' => '1.8.5',
+ 'version' => '1.8.5.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../guzzlehttp/psr7',
+ 'aliases' => array(),
+ 'reference' => '337e3ad8e5716c15f9657bd214d16cc5e69df268',
+ 'dev_requirement' => false,
+ ),
+ 'icinga/icinga-php-thirdparty' => array(
+ 'pretty_version' => 'dev-main',
+ 'version' => 'dev-main',
+ 'type' => 'project',
+ 'install_path' => __DIR__ . '/../../',
+ 'aliases' => array(),
+ 'reference' => '2b056ffa5b22c875d59d33572e4bdaa529de53c5',
+ 'dev_requirement' => false,
+ ),
+ 'jfcherng/php-color-output' => array(
+ 'pretty_version' => '2.0.2',
+ 'version' => '2.0.2.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../jfcherng/php-color-output',
+ 'aliases' => array(),
+ 'reference' => '2673074597eca9682d2fdfaee39a22418d4cc2f6',
+ 'dev_requirement' => false,
+ ),
+ 'jfcherng/php-diff' => array(
+ 'pretty_version' => '6.10.4',
+ 'version' => '6.10.4.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../jfcherng/php-diff',
+ 'aliases' => array(),
+ 'reference' => 'ccc178b81ac737b0f9a60e7210d26d5ed797e786',
+ 'dev_requirement' => false,
+ ),
+ 'jfcherng/php-mb-string' => array(
+ 'pretty_version' => '1.4.6',
+ 'version' => '1.4.6.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../jfcherng/php-mb-string',
+ 'aliases' => array(),
+ 'reference' => 'f5b438d348e030961e0b86a04ef2319c31ae8146',
+ 'dev_requirement' => false,
+ ),
+ 'jfcherng/php-sequence-matcher' => array(
+ 'pretty_version' => '3.2.8',
+ 'version' => '3.2.8.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../jfcherng/php-sequence-matcher',
+ 'aliases' => array(),
+ 'reference' => '410519ca07cd7989f450d6e2aa40975dbd1be048',
+ 'dev_requirement' => false,
+ ),
+ 'paragonie/random_compat' => array(
+ 'pretty_version' => 'v9.99.100',
+ 'version' => '9.99.100.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../paragonie/random_compat',
+ 'aliases' => array(),
+ 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
+ 'dev_requirement' => false,
+ ),
+ 'predis/predis' => array(
+ 'pretty_version' => 'v1.1.10',
+ 'version' => '1.1.10.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../predis/predis',
+ 'aliases' => array(),
+ 'reference' => 'a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e',
+ 'dev_requirement' => false,
+ ),
+ 'psr/http-message' => array(
+ 'pretty_version' => '1.0.1',
+ 'version' => '1.0.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../psr/http-message',
+ 'aliases' => array(),
+ 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
+ 'dev_requirement' => false,
+ ),
+ 'psr/http-message-implementation' => array(
+ 'dev_requirement' => false,
+ 'provided' => array(
+ 0 => '1.0',
+ ),
+ ),
+ 'ralouphie/getallheaders' => array(
+ 'pretty_version' => '3.0.3',
+ 'version' => '3.0.3.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../ralouphie/getallheaders',
+ 'aliases' => array(),
+ 'reference' => '120b605dfeb996808c31b6477290a714d356e822',
+ 'dev_requirement' => false,
+ ),
+ 'ramsey/uuid' => array(
+ 'pretty_version' => '3.9.6',
+ 'version' => '3.9.6.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../ramsey/uuid',
+ 'aliases' => array(),
+ 'reference' => 'ffa80ab953edd85d5b6c004f96181a538aad35a3',
+ 'dev_requirement' => false,
+ ),
+ 'react/cache' => array(
+ 'pretty_version' => 'v1.1.1',
+ 'version' => '1.1.1.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/cache',
+ 'aliases' => array(),
+ 'reference' => '4bf736a2cccec7298bdf745db77585966fc2ca7e',
+ 'dev_requirement' => false,
+ ),
+ 'react/child-process' => array(
+ 'pretty_version' => 'v0.6.4',
+ 'version' => '0.6.4.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/child-process',
+ 'aliases' => array(),
+ 'reference' => 'a778f3fb828d68caf8a9ab6567fd8342a86f12fe',
+ 'dev_requirement' => false,
+ ),
+ 'react/datagram' => array(
+ 'pretty_version' => 'v1.8.0',
+ 'version' => '1.8.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/datagram',
+ 'aliases' => array(),
+ 'reference' => '40f2c39f83541367018605a73b57c99186f7145c',
+ 'dev_requirement' => false,
+ ),
+ 'react/dns' => array(
+ 'pretty_version' => 'v1.9.0',
+ 'version' => '1.9.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/dns',
+ 'aliases' => array(),
+ 'reference' => '6d38296756fa644e6cb1bfe95eff0f9a4ed6edcb',
+ 'dev_requirement' => false,
+ ),
+ 'react/event-loop' => array(
+ 'pretty_version' => 'v1.3.0',
+ 'version' => '1.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/event-loop',
+ 'aliases' => array(),
+ 'reference' => '187fb56f46d424afb6ec4ad089269c72eec2e137',
+ 'dev_requirement' => false,
+ ),
+ 'react/http' => array(
+ 'pretty_version' => 'v1.6.0',
+ 'version' => '1.6.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/http',
+ 'aliases' => array(),
+ 'reference' => '59961cc4a5b14481728f07c591546be18fa3a5c7',
+ 'dev_requirement' => false,
+ ),
+ 'react/http-client' => array(
+ 'pretty_version' => 'v0.5.11',
+ 'version' => '0.5.11.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/http-client',
+ 'aliases' => array(),
+ 'reference' => '23dddb415b9bd36c81d1c78df63143e65702aa4b',
+ 'dev_requirement' => false,
+ ),
+ 'react/promise' => array(
+ 'pretty_version' => 'v2.9.0',
+ 'version' => '2.9.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/promise',
+ 'aliases' => array(),
+ 'reference' => '234f8fd1023c9158e2314fa9d7d0e6a83db42910',
+ 'dev_requirement' => false,
+ ),
+ 'react/promise-stream' => array(
+ 'pretty_version' => 'v1.3.0',
+ 'version' => '1.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/promise-stream',
+ 'aliases' => array(),
+ 'reference' => '3ebd94fe0d8edbf44937948af28d02d5437e9949',
+ 'dev_requirement' => false,
+ ),
+ 'react/promise-timer' => array(
+ 'pretty_version' => 'v1.9.0',
+ 'version' => '1.9.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/promise-timer',
+ 'aliases' => array(),
+ 'reference' => 'aa7a73c74b8d8c0f622f5982ff7b0351bc29e495',
+ 'dev_requirement' => false,
+ ),
+ 'react/socket' => array(
+ 'pretty_version' => 'v1.11.0',
+ 'version' => '1.11.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/socket',
+ 'aliases' => array(),
+ 'reference' => 'f474156aaab4f09041144fa8b57c7d70aed32a1c',
+ 'dev_requirement' => false,
+ ),
+ 'react/stream' => array(
+ 'pretty_version' => 'v1.2.0',
+ 'version' => '1.2.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../react/stream',
+ 'aliases' => array(),
+ 'reference' => '7a423506ee1903e89f1e08ec5f0ed430ff784ae9',
+ 'dev_requirement' => false,
+ ),
+ 'rhumsaa/uuid' => array(
+ 'dev_requirement' => false,
+ 'replaced' => array(
+ 0 => '3.9.6',
+ ),
+ ),
+ 'ringcentral/psr7' => array(
+ 'pretty_version' => '1.3.0',
+ 'version' => '1.3.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../ringcentral/psr7',
+ 'aliases' => array(),
+ 'reference' => '360faaec4b563958b673fb52bbe94e37f14bc686',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-ctype' => array(
+ 'pretty_version' => 'v1.26.0',
+ 'version' => '1.26.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
+ 'aliases' => array(),
+ 'reference' => '6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-intl-idn' => array(
+ 'pretty_version' => 'v1.26.0',
+ 'version' => '1.26.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
+ 'aliases' => array(),
+ 'reference' => '59a8d271f00dd0e4c2e518104cc7963f655a1aa8',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-intl-normalizer' => array(
+ 'pretty_version' => 'v1.26.0',
+ 'version' => '1.26.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
+ 'aliases' => array(),
+ 'reference' => '219aa369ceff116e673852dce47c3a41794c14bd',
+ 'dev_requirement' => false,
+ ),
+ 'symfony/polyfill-php72' => array(
+ 'pretty_version' => 'v1.26.0',
+ 'version' => '1.26.0.0',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../symfony/polyfill-php72',
+ 'aliases' => array(),
+ 'reference' => 'bf44a9fd41feaac72b074de600314a93e2ae78e2',
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php
new file mode 100644
index 0000000..589e9e7
--- /dev/null
+++ b/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+<?php
+
+// platform_check.php @generated by Composer
+
+$issues = array();
+
+if (!(PHP_VERSION_ID >= 70200)) {
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+ if (!headers_sent()) {
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+ if (!ini_get('display_errors')) {
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+ } elseif (!headers_sent()) {
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+ }
+ }
+ trigger_error(
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
+ E_USER_ERROR
+ );
+}
diff --git a/vendor/cweagans/composer-patches/composer.json b/vendor/cweagans/composer-patches/composer.json
new file mode 100644
index 0000000..1565b02
--- /dev/null
+++ b/vendor/cweagans/composer-patches/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "cweagans/composer-patches",
+ "description": "Provides a way to patch Composer packages.",
+ "minimum-stability": "dev",
+ "license": "BSD-3-Clause",
+ "type": "composer-plugin",
+ "extra": {
+ "class": "cweagans\\Composer\\Patches"
+ },
+ "authors": [
+ {
+ "name": "Cameron Eagans",
+ "email": "me@cweagans.net"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "composer-plugin-api": "^1.0 || ^2.0"
+ },
+ "require-dev": {
+ "composer/composer": "~1.0 || ~2.0",
+ "phpunit/phpunit": "~4.6"
+ },
+ "autoload": {
+ "psr-4": {"cweagans\\Composer\\": "src"}
+ },
+ "autoload-dev": {
+ "psr-4": {"cweagans\\Composer\\Tests\\": "tests"}
+ }
+}
diff --git a/vendor/cweagans/composer-patches/src/PatchEvent.php b/vendor/cweagans/composer-patches/src/PatchEvent.php
new file mode 100644
index 0000000..31d36f8
--- /dev/null
+++ b/vendor/cweagans/composer-patches/src/PatchEvent.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Dispatch events when patches are applied.
+ */
+
+namespace cweagans\Composer;
+
+use Composer\EventDispatcher\Event;
+use Composer\Package\PackageInterface;
+
+class PatchEvent extends Event {
+
+ /**
+ * @var PackageInterface $package
+ */
+ protected $package;
+ /**
+ * @var string $url
+ */
+ protected $url;
+ /**
+ * @var string $description
+ */
+ protected $description;
+
+ /**
+ * Constructs a PatchEvent object.
+ *
+ * @param string $eventName
+ * @param PackageInterface $package
+ * @param string $url
+ * @param string $description
+ */
+ public function __construct($eventName, PackageInterface $package, $url, $description) {
+ parent::__construct($eventName);
+ $this->package = $package;
+ $this->url = $url;
+ $this->description = $description;
+ }
+
+ /**
+ * Returns the package that is patched.
+ *
+ * @return PackageInterface
+ */
+ public function getPackage() {
+ return $this->package;
+ }
+
+ /**
+ * Returns the url of the patch.
+ *
+ * @return string
+ */
+ public function getUrl() {
+ return $this->url;
+ }
+
+ /**
+ * Returns the description of the patch.
+ *
+ * @return string
+ */
+ public function getDescription() {
+ return $this->description;
+ }
+
+}
diff --git a/vendor/cweagans/composer-patches/src/PatchEvents.php b/vendor/cweagans/composer-patches/src/PatchEvents.php
new file mode 100644
index 0000000..ecee947
--- /dev/null
+++ b/vendor/cweagans/composer-patches/src/PatchEvents.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Dispatch events when patches are applied.
+ */
+
+namespace cweagans\Composer;
+
+class PatchEvents {
+
+ /**
+ * The PRE_PATCH_APPLY event occurs before a patch is applied.
+ *
+ * The event listener method receives a cweagans\Composer\PatchEvent instance.
+ *
+ * @var string
+ */
+ const PRE_PATCH_APPLY = 'pre-patch-apply';
+
+ /**
+ * The POST_PATCH_APPLY event occurs after a patch is applied.
+ *
+ * The event listener method receives a cweagans\Composer\PatchEvent instance.
+ *
+ * @var string
+ */
+ const POST_PATCH_APPLY = 'post-patch-apply';
+
+}
diff --git a/vendor/cweagans/composer-patches/src/Patches.php b/vendor/cweagans/composer-patches/src/Patches.php
new file mode 100644
index 0000000..52e4203
--- /dev/null
+++ b/vendor/cweagans/composer-patches/src/Patches.php
@@ -0,0 +1,594 @@
+<?php
+
+/**
+ * @file
+ * Provides a way to patch Composer packages after installation.
+ */
+
+namespace cweagans\Composer;
+
+use Composer\Composer;
+use Composer\DependencyResolver\Operation\InstallOperation;
+use Composer\DependencyResolver\Operation\UninstallOperation;
+use Composer\DependencyResolver\Operation\UpdateOperation;
+use Composer\DependencyResolver\Operation\OperationInterface;
+use Composer\EventDispatcher\EventSubscriberInterface;
+use Composer\IO\IOInterface;
+use Composer\Package\AliasPackage;
+use Composer\Package\PackageInterface;
+use Composer\Plugin\PluginInterface;
+use Composer\Installer\PackageEvents;
+use Composer\Script\Event;
+use Composer\Script\ScriptEvents;
+use Composer\Installer\PackageEvent;
+use Composer\Util\ProcessExecutor;
+use Composer\Util\RemoteFilesystem;
+use Symfony\Component\Process\Process;
+
+class Patches implements PluginInterface, EventSubscriberInterface {
+
+ /**
+ * @var Composer $composer
+ */
+ protected $composer;
+ /**
+ * @var IOInterface $io
+ */
+ protected $io;
+ /**
+ * @var EventDispatcher $eventDispatcher
+ */
+ protected $eventDispatcher;
+ /**
+ * @var ProcessExecutor $executor
+ */
+ protected $executor;
+ /**
+ * @var array $patches
+ */
+ protected $patches;
+
+ /**
+ * Apply plugin modifications to composer
+ *
+ * @param Composer $composer
+ * @param IOInterface $io
+ */
+ public function activate(Composer $composer, IOInterface $io) {
+ $this->composer = $composer;
+ $this->io = $io;
+ $this->eventDispatcher = $composer->getEventDispatcher();
+ $this->executor = new ProcessExecutor($this->io);
+ $this->patches = array();
+ $this->installedPatches = array();
+ }
+
+ /**
+ * Returns an array of event names this subscriber wants to listen to.
+ */
+ public static function getSubscribedEvents() {
+ return array(
+ ScriptEvents::PRE_INSTALL_CMD => array('checkPatches'),
+ ScriptEvents::PRE_UPDATE_CMD => array('checkPatches'),
+ PackageEvents::PRE_PACKAGE_INSTALL => array('gatherPatches'),
+ PackageEvents::PRE_PACKAGE_UPDATE => array('gatherPatches'),
+ // The following is a higher weight for compatibility with
+ // https://github.com/AydinHassan/magento-core-composer-installer and more generally for compatibility with
+ // every Composer plugin which deploys downloaded packages to other locations.
+ // In such cases you want that those plugins deploy patched files so they have to run after
+ // the "composer-patches" plugin.
+ // @see: https://github.com/cweagans/composer-patches/pull/153
+ PackageEvents::POST_PACKAGE_INSTALL => array('postInstall', 10),
+ PackageEvents::POST_PACKAGE_UPDATE => array('postInstall', 10),
+ );
+ }
+
+ /**
+ * Before running composer install,
+ * @param Event $event
+ */
+ public function checkPatches(Event $event) {
+ if (!$this->isPatchingEnabled()) {
+ return;
+ }
+
+ try {
+ $repositoryManager = $this->composer->getRepositoryManager();
+ $localRepository = $repositoryManager->getLocalRepository();
+ $installationManager = $this->composer->getInstallationManager();
+ $packages = $localRepository->getPackages();
+
+ $extra = $this->composer->getPackage()->getExtra();
+ $patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
+
+ $tmp_patches = $this->grabPatches();
+ foreach ($packages as $package) {
+ $extra = $package->getExtra();
+ if (isset($extra['patches'])) {
+ if (isset($patches_ignore[$package->getName()])) {
+ foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
+ if (isset($extra['patches'][$package_name])) {
+ $extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
+ }
+ }
+ }
+ $this->installedPatches[$package->getName()] = $extra['patches'];
+ }
+ $patches = isset($extra['patches']) ? $extra['patches'] : array();
+ $tmp_patches = $this->arrayMergeRecursiveDistinct($tmp_patches, $patches);
+ }
+
+ if ($tmp_patches == FALSE) {
+ $this->io->write('<info>No patches supplied.</info>');
+ return;
+ }
+
+ // Remove packages for which the patch set has changed.
+ $promises = array();
+ foreach ($packages as $package) {
+ if (!($package instanceof AliasPackage)) {
+ $package_name = $package->getName();
+ $extra = $package->getExtra();
+ $has_patches = isset($tmp_patches[$package_name]);
+ $has_applied_patches = isset($extra['patches_applied']) && count($extra['patches_applied']) > 0;
+ if (($has_patches && !$has_applied_patches)
+ || (!$has_patches && $has_applied_patches)
+ || ($has_patches && $has_applied_patches && $tmp_patches[$package_name] !== $extra['patches_applied'])) {
+ $uninstallOperation = new UninstallOperation($package, 'Removing package so it can be re-installed and re-patched.');
+ $this->io->write('<info>Removing package ' . $package_name . ' so that it can be re-installed and re-patched.</info>');
+ $promises[] = $installationManager->uninstall($localRepository, $uninstallOperation);
+ }
+ }
+ }
+ $promises = array_filter($promises);
+ if ($promises) {
+ $this->composer->getLoop()->wait($promises);
+ }
+ }
+ // If the Locker isn't available, then we don't need to do this.
+ // It's the first time packages have been installed.
+ catch (\LogicException $e) {
+ return;
+ }
+ }
+
+ /**
+ * Gather patches from dependencies and store them for later use.
+ *
+ * @param PackageEvent $event
+ */
+ public function gatherPatches(PackageEvent $event) {
+ // If we've already done this, then don't do it again.
+ if (isset($this->patches['_patchesGathered'])) {
+ $this->io->write('<info>Patches already gathered. Skipping</info>', TRUE, IOInterface::VERBOSE);
+ return;
+ }
+ // If patching has been disabled, bail out here.
+ elseif (!$this->isPatchingEnabled()) {
+ $this->io->write('<info>Patching is disabled. Skipping.</info>', TRUE, IOInterface::VERBOSE);
+ return;
+ }
+
+ $this->patches = $this->grabPatches();
+ if (empty($this->patches)) {
+ $this->io->write('<info>No patches supplied.</info>');
+ }
+
+ $extra = $this->composer->getPackage()->getExtra();
+ $patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
+
+ // Now add all the patches from dependencies that will be installed.
+ $operations = $event->getOperations();
+ $this->io->write('<info>Gathering patches for dependencies. This might take a minute.</info>');
+ foreach ($operations as $operation) {
+ if ($operation instanceof InstallOperation || $operation instanceof UpdateOperation) {
+ $package = $this->getPackageFromOperation($operation);
+ $extra = $package->getExtra();
+ if (isset($extra['patches'])) {
+ if (isset($patches_ignore[$package->getName()])) {
+ foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
+ if (isset($extra['patches'][$package_name])) {
+ $extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
+ }
+ }
+ }
+ $this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $extra['patches']);
+ }
+ // Unset installed patches for this package
+ if(isset($this->installedPatches[$package->getName()])) {
+ unset($this->installedPatches[$package->getName()]);
+ }
+ }
+ }
+
+ // Merge installed patches from dependencies that did not receive an update.
+ foreach ($this->installedPatches as $patches) {
+ $this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $patches);
+ }
+
+ // If we're in verbose mode, list the projects we're going to patch.
+ if ($this->io->isVerbose()) {
+ foreach ($this->patches as $package => $patches) {
+ $number = count($patches);
+ $this->io->write('<info>Found ' . $number . ' patches for ' . $package . '.</info>');
+ }
+ }
+
+ // Make sure we don't gather patches again. Extra keys in $this->patches
+ // won't hurt anything, so we'll just stash it there.
+ $this->patches['_patchesGathered'] = TRUE;
+ }
+
+ /**
+ * Get the patches from root composer or external file
+ * @return Patches
+ * @throws \Exception
+ */
+ public function grabPatches() {
+ // First, try to get the patches from the root composer.json.
+ $extra = $this->composer->getPackage()->getExtra();
+ if (isset($extra['patches'])) {
+ $this->io->write('<info>Gathering patches for root package.</info>');
+ $patches = $extra['patches'];
+ return $patches;
+ }
+ // If it's not specified there, look for a patches-file definition.
+ elseif (isset($extra['patches-file'])) {
+ $this->io->write('<info>Gathering patches from patch file.</info>');
+ $patches = file_get_contents($extra['patches-file']);
+ $patches = json_decode($patches, TRUE);
+ $error = json_last_error();
+ if ($error != 0) {
+ switch ($error) {
+ case JSON_ERROR_DEPTH:
+ $msg = ' - Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $msg = ' - Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $msg = ' - Unexpected control character found';
+ break;
+ case JSON_ERROR_SYNTAX:
+ $msg = ' - Syntax error, malformed JSON';
+ break;
+ case JSON_ERROR_UTF8:
+ $msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $msg = ' - Unknown error';
+ break;
+ }
+ throw new \Exception('There was an error in the supplied patches file:' . $msg);
+ }
+ if (isset($patches['patches'])) {
+ $patches = $patches['patches'];
+ return $patches;
+ }
+ elseif(!$patches) {
+ throw new \Exception('There was an error in the supplied patch file');
+ }
+ }
+ else {
+ return array();
+ }
+ }
+
+ /**
+ * @param PackageEvent $event
+ * @throws \Exception
+ */
+ public function postInstall(PackageEvent $event) {
+
+ // Check if we should exit in failure.
+ $extra = $this->composer->getPackage()->getExtra();
+ $exitOnFailure = getenv('COMPOSER_EXIT_ON_PATCH_FAILURE') || !empty($extra['composer-exit-on-patch-failure']);
+ $skipReporting = getenv('COMPOSER_PATCHES_SKIP_REPORTING') || !empty($extra['composer-patches-skip-reporting']);
+
+ // Get the package object for the current operation.
+ $operation = $event->getOperation();
+ /** @var PackageInterface $package */
+ $package = $this->getPackageFromOperation($operation);
+ $package_name = $package->getName();
+
+ if (!isset($this->patches[$package_name])) {
+ if ($this->io->isVerbose()) {
+ $this->io->write('<info>No patches found for ' . $package_name . '.</info>');
+ }
+ return;
+ }
+ $this->io->write(' - Applying patches for <info>' . $package_name . '</info>');
+
+ // Get the install path from the package object.
+ $manager = $event->getComposer()->getInstallationManager();
+ $install_path = $manager->getInstaller($package->getType())->getInstallPath($package);
+
+ // Set up a downloader.
+ $downloader = new RemoteFilesystem($this->io, $this->composer->getConfig());
+
+ // Track applied patches in the package info in installed.json
+ $localRepository = $this->composer->getRepositoryManager()->getLocalRepository();
+ $localPackage = $localRepository->findPackage($package_name, $package->getVersion());
+ $extra = $localPackage->getExtra();
+ $extra['patches_applied'] = array();
+
+ foreach ($this->patches[$package_name] as $description => $url) {
+ $this->io->write(' <info>' . $url . '</info> (<comment>' . $description. '</comment>)');
+ try {
+ $this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $package, $url, $description));
+ $this->getAndApplyPatch($downloader, $install_path, $url, $package);
+ $this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::POST_PATCH_APPLY, $package, $url, $description));
+ $extra['patches_applied'][$description] = $url;
+ }
+ catch (\Exception $e) {
+ $this->io->write(' <error>Could not apply patch! Skipping. The error was: ' . $e->getMessage() . '</error>');
+ if ($exitOnFailure) {
+ throw new \Exception("Cannot apply patch $description ($url)!");
+ }
+ }
+ }
+ $localPackage->setExtra($extra);
+
+ $this->io->write('');
+
+ if (true !== $skipReporting) {
+ $this->writePatchReport($this->patches[$package_name], $install_path);
+ }
+ }
+
+ /**
+ * Get a Package object from an OperationInterface object.
+ *
+ * @param OperationInterface $operation
+ * @return PackageInterface
+ * @throws \Exception
+ */
+ protected function getPackageFromOperation(OperationInterface $operation) {
+ if ($operation instanceof InstallOperation) {
+ $package = $operation->getPackage();
+ }
+ elseif ($operation instanceof UpdateOperation) {
+ $package = $operation->getTargetPackage();
+ }
+ else {
+ throw new \Exception('Unknown operation: ' . get_class($operation));
+ }
+
+ return $package;
+ }
+
+ /**
+ * Apply a patch on code in the specified directory.
+ *
+ * @param RemoteFilesystem $downloader
+ * @param $install_path
+ * @param $patch_url
+ * @param PackageInterface $package
+ * @throws \Exception
+ */
+ protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, $patch_url, PackageInterface $package) {
+
+ // Local patch file.
+ if (file_exists($patch_url)) {
+ $filename = realpath($patch_url);
+ }
+ else {
+ // Generate random (but not cryptographically so) filename.
+ $filename = uniqid(sys_get_temp_dir().'/') . ".patch";
+
+ // Download file from remote filesystem to this location.
+ $hostname = parse_url($patch_url, PHP_URL_HOST);
+
+ try {
+ $downloader->copy($hostname, $patch_url, $filename, false);
+ } catch (\Exception $e) {
+ // In case of an exception, retry once as the download might
+ // have failed due to intermittent network issues.
+ $downloader->copy($hostname, $patch_url, $filename, false);
+ }
+ }
+
+ // The order here is intentional. p1 is most likely to apply with git apply.
+ // p0 is next likely. p2 is extremely unlikely, but for some special cases,
+ // it might be useful. p4 is useful for Magento 2 patches
+ $patch_levels = array('-p1', '-p0', '-p2', '-p4');
+
+ // Check for specified patch level for this package.
+ $extra = $this->composer->getPackage()->getExtra();
+ if (!empty($extra['patchLevel'][$package->getName()])){
+ $patch_levels = array($extra['patchLevel'][$package->getName()]);
+ }
+ // Attempt to apply with git apply.
+ $patched = $this->applyPatchWithGit($install_path, $patch_levels, $filename);
+
+ // In some rare cases, git will fail to apply a patch, fallback to using
+ // the 'patch' command.
+ if (!$patched) {
+ foreach ($patch_levels as $patch_level) {
+ // --no-backup-if-mismatch here is a hack that fixes some
+ // differences between how patch works on windows and unix.
+ if ($patched = $this->executeCommand("patch %s --no-backup-if-mismatch -d %s < %s", $patch_level, $install_path, $filename)) {
+ break;
+ }
+ }
+ }
+
+ // Clean up the temporary patch file.
+ if (isset($hostname)) {
+ unlink($filename);
+ }
+ // If the patch *still* isn't applied, then give up and throw an Exception.
+ // Otherwise, let the user know it worked.
+ if (!$patched) {
+ throw new \Exception("Cannot apply patch $patch_url");
+ }
+ }
+
+ /**
+ * Checks if the root package enables patching.
+ *
+ * @return bool
+ * Whether patching is enabled. Defaults to TRUE.
+ */
+ protected function isPatchingEnabled() {
+ $extra = $this->composer->getPackage()->getExtra();
+
+ if (empty($extra['patches']) && empty($extra['patches-ignore']) && !isset($extra['patches-file'])) {
+ // The root package has no patches of its own, so only allow patching if
+ // it has specifically opted in.
+ return isset($extra['enable-patching']) ? $extra['enable-patching'] : FALSE;
+ }
+ else {
+ return TRUE;
+ }
+ }
+
+ /**
+ * Writes a patch report to the target directory.
+ *
+ * @param array $patches
+ * @param string $directory
+ */
+ protected function writePatchReport($patches, $directory) {
+ $output = "This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)\n";
+ $output .= "Patches applied to this directory:\n\n";
+ foreach ($patches as $description => $url) {
+ $output .= $description . "\n";
+ $output .= 'Source: ' . $url . "\n\n\n";
+ }
+ file_put_contents($directory . "/PATCHES.txt", $output);
+ }
+
+ /**
+ * Executes a shell command with escaping.
+ *
+ * @param string $cmd
+ * @return bool
+ */
+ protected function executeCommand($cmd) {
+ // Shell-escape all arguments except the command.
+ $args = func_get_args();
+ foreach ($args as $index => $arg) {
+ if ($index !== 0) {
+ $args[$index] = escapeshellarg($arg);
+ }
+ }
+
+ // And replace the arguments.
+ $command = call_user_func_array('sprintf', $args);
+ $output = '';
+ if ($this->io->isVerbose()) {
+ $this->io->write('<comment>' . $command . '</comment>');
+ $io = $this->io;
+ $output = function ($type, $data) use ($io) {
+ if ($type == Process::ERR) {
+ $io->write('<error>' . $data . '</error>');
+ }
+ else {
+ $io->write('<comment>' . $data . '</comment>');
+ }
+ };
+ }
+ return ($this->executor->execute($command, $output) == 0);
+ }
+
+ /**
+ * Recursively merge arrays without changing data types of values.
+ *
+ * Does not change the data types of the values in the arrays. Matching keys'
+ * values in the second array overwrite those in the first array, as is the
+ * case with array_merge.
+ *
+ * @param array $array1
+ * The first array.
+ * @param array $array2
+ * The second array.
+ * @return array
+ * The merged array.
+ *
+ * @see http://php.net/manual/en/function.array-merge-recursive.php#92195
+ */
+ protected function arrayMergeRecursiveDistinct(array $array1, array $array2) {
+ $merged = $array1;
+
+ foreach ($array2 as $key => &$value) {
+ if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
+ $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
+ }
+ else {
+ $merged[$key] = $value;
+ }
+ }
+
+ return $merged;
+ }
+
+ /**
+ * Attempts to apply a patch with git apply.
+ *
+ * @param $install_path
+ * @param $patch_levels
+ * @param $filename
+ *
+ * @return bool
+ * TRUE if patch was applied, FALSE otherwise.
+ */
+ protected function applyPatchWithGit($install_path, $patch_levels, $filename) {
+ // Do not use git apply unless the install path is itself a git repo
+ // @see https://stackoverflow.com/a/27283285
+ if (!is_dir($install_path . '/.git')) {
+ return FALSE;
+ }
+
+ $patched = FALSE;
+ foreach ($patch_levels as $patch_level) {
+ if ($this->io->isVerbose()) {
+ $comment = 'Testing ability to patch with git apply.';
+ $comment .= ' This command may produce errors that can be safely ignored.';
+ $this->io->write('<comment>' . $comment . '</comment>');
+ }
+ $checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename);
+ $output = $this->executor->getErrorOutput();
+ if (substr($output, 0, 7) == 'Skipped') {
+ // Git will indicate success but silently skip patches in some scenarios.
+ //
+ // @see https://github.com/cweagans/composer-patches/pull/165
+ $checked = FALSE;
+ }
+ if ($checked) {
+ // Apply the first successful style.
+ $patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename);
+ break;
+ }
+ }
+ return $patched;
+ }
+
+ /**
+ * Indicates if a package has been patched.
+ *
+ * @param \Composer\Package\PackageInterface $package
+ * The package to check.
+ *
+ * @return bool
+ * TRUE if the package has been patched.
+ */
+ public static function isPackagePatched(PackageInterface $package) {
+ return array_key_exists('patches_applied', $package->getExtra());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function deactivate(Composer $composer, IOInterface $io)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function uninstall(Composer $composer, IOInterface $io)
+ {
+ }
+
+}
diff --git a/vendor/evenement/evenement/LICENSE b/vendor/evenement/evenement/LICENSE
new file mode 100644
index 0000000..d9a37d0
--- /dev/null
+++ b/vendor/evenement/evenement/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Igor Wiedler
+
+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/evenement/evenement/composer.json b/vendor/evenement/evenement/composer.json
new file mode 100644
index 0000000..cbb4827
--- /dev/null
+++ b/vendor/evenement/evenement/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "evenement/evenement",
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": ["event-dispatcher", "event-emitter"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "autoload": {
+ "psr-0": {
+ "Evenement": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-0": {
+ "Evenement": "tests"
+ },
+ "files": ["tests/Evenement/Tests/functions.php"]
+ }
+}
diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitter.php b/vendor/evenement/evenement/src/Evenement/EventEmitter.php
new file mode 100644
index 0000000..db189b9
--- /dev/null
+++ b/vendor/evenement/evenement/src/Evenement/EventEmitter.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of Evenement.
+ *
+ * (c) Igor Wiedler <igor@wiedler.ch>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Evenement;
+
+class EventEmitter implements EventEmitterInterface
+{
+ use EventEmitterTrait;
+}
diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php b/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php
new file mode 100644
index 0000000..310631a
--- /dev/null
+++ b/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php
@@ -0,0 +1,22 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of Evenement.
+ *
+ * (c) Igor Wiedler <igor@wiedler.ch>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Evenement;
+
+interface EventEmitterInterface
+{
+ public function on($event, callable $listener);
+ public function once($event, callable $listener);
+ public function removeListener($event, callable $listener);
+ public function removeAllListeners($event = null);
+ public function listeners($event = null);
+ public function emit($event, array $arguments = []);
+}
diff --git a/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php b/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php
new file mode 100644
index 0000000..a78e65c
--- /dev/null
+++ b/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php
@@ -0,0 +1,135 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of Evenement.
+ *
+ * (c) Igor Wiedler <igor@wiedler.ch>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Evenement;
+
+use InvalidArgumentException;
+
+trait EventEmitterTrait
+{
+ protected $listeners = [];
+ protected $onceListeners = [];
+
+ public function on($event, callable $listener)
+ {
+ if ($event === null) {
+ throw new InvalidArgumentException('event name must not be null');
+ }
+
+ if (!isset($this->listeners[$event])) {
+ $this->listeners[$event] = [];
+ }
+
+ $this->listeners[$event][] = $listener;
+
+ return $this;
+ }
+
+ public function once($event, callable $listener)
+ {
+ if ($event === null) {
+ throw new InvalidArgumentException('event name must not be null');
+ }
+
+ if (!isset($this->onceListeners[$event])) {
+ $this->onceListeners[$event] = [];
+ }
+
+ $this->onceListeners[$event][] = $listener;
+
+ return $this;
+ }
+
+ public function removeListener($event, callable $listener)
+ {
+ if ($event === null) {
+ throw new InvalidArgumentException('event name must not be null');
+ }
+
+ if (isset($this->listeners[$event])) {
+ $index = \array_search($listener, $this->listeners[$event], true);
+ if (false !== $index) {
+ unset($this->listeners[$event][$index]);
+ if (\count($this->listeners[$event]) === 0) {
+ unset($this->listeners[$event]);
+ }
+ }
+ }
+
+ if (isset($this->onceListeners[$event])) {
+ $index = \array_search($listener, $this->onceListeners[$event], true);
+ if (false !== $index) {
+ unset($this->onceListeners[$event][$index]);
+ if (\count($this->onceListeners[$event]) === 0) {
+ unset($this->onceListeners[$event]);
+ }
+ }
+ }
+ }
+
+ public function removeAllListeners($event = null)
+ {
+ if ($event !== null) {
+ unset($this->listeners[$event]);
+ } else {
+ $this->listeners = [];
+ }
+
+ if ($event !== null) {
+ unset($this->onceListeners[$event]);
+ } else {
+ $this->onceListeners = [];
+ }
+ }
+
+ public function listeners($event = null): array
+ {
+ if ($event === null) {
+ $events = [];
+ $eventNames = \array_unique(
+ \array_merge(\array_keys($this->listeners), \array_keys($this->onceListeners))
+ );
+ foreach ($eventNames as $eventName) {
+ $events[$eventName] = \array_merge(
+ isset($this->listeners[$eventName]) ? $this->listeners[$eventName] : [],
+ isset($this->onceListeners[$eventName]) ? $this->onceListeners[$eventName] : []
+ );
+ }
+ return $events;
+ }
+
+ return \array_merge(
+ isset($this->listeners[$event]) ? $this->listeners[$event] : [],
+ isset($this->onceListeners[$event]) ? $this->onceListeners[$event] : []
+ );
+ }
+
+ public function emit($event, array $arguments = [])
+ {
+ if ($event === null) {
+ throw new InvalidArgumentException('event name must not be null');
+ }
+
+ if (isset($this->listeners[$event])) {
+ foreach ($this->listeners[$event] as $listener) {
+ $listener(...$arguments);
+ }
+ }
+
+ if (isset($this->onceListeners[$event])) {
+ $listeners = $this->onceListeners[$event];
+ unset($this->onceListeners[$event]);
+ foreach ($listeners as $listener) {
+ $listener(...$arguments);
+ }
+ }
+ }
+}
diff --git a/vendor/fig/http-message-util/LICENSE b/vendor/fig/http-message-util/LICENSE
new file mode 100644
index 0000000..e2fa347
--- /dev/null
+++ b/vendor/fig/http-message-util/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2016 PHP Framework Interoperability Group
+
+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/fig/http-message-util/composer.json b/vendor/fig/http-message-util/composer.json
new file mode 100644
index 0000000..8645893
--- /dev/null
+++ b/vendor/fig/http-message-util/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "fig/http-message-util",
+ "description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
+ "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": "^5.3 || ^7.0 || ^8.0"
+ },
+ "suggest": {
+ "psr/http-message": "The package containing the PSR-7 interfaces"
+ },
+ "autoload": {
+ "psr-4": {
+ "Fig\\Http\\Message\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ }
+}
diff --git a/vendor/fig/http-message-util/src/RequestMethodInterface.php b/vendor/fig/http-message-util/src/RequestMethodInterface.php
new file mode 100644
index 0000000..97d9a93
--- /dev/null
+++ b/vendor/fig/http-message-util/src/RequestMethodInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Fig\Http\Message;
+
+/**
+ * Defines constants for common HTTP request methods.
+ *
+ * Usage:
+ *
+ * <code>
+ * class RequestFactory implements RequestMethodInterface
+ * {
+ * public static function factory(
+ * $uri = '/',
+ * $method = self::METHOD_GET,
+ * $data = []
+ * ) {
+ * }
+ * }
+ * </code>
+ */
+interface RequestMethodInterface
+{
+ const METHOD_HEAD = 'HEAD';
+ const METHOD_GET = 'GET';
+ const METHOD_POST = 'POST';
+ const METHOD_PUT = 'PUT';
+ const METHOD_PATCH = 'PATCH';
+ const METHOD_DELETE = 'DELETE';
+ const METHOD_PURGE = 'PURGE';
+ const METHOD_OPTIONS = 'OPTIONS';
+ const METHOD_TRACE = 'TRACE';
+ const METHOD_CONNECT = 'CONNECT';
+}
diff --git a/vendor/fig/http-message-util/src/StatusCodeInterface.php b/vendor/fig/http-message-util/src/StatusCodeInterface.php
new file mode 100644
index 0000000..99b7e78
--- /dev/null
+++ b/vendor/fig/http-message-util/src/StatusCodeInterface.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Fig\Http\Message;
+
+/**
+ * Defines constants for common HTTP status code.
+ *
+ * @see https://tools.ietf.org/html/rfc2295#section-8.1
+ * @see https://tools.ietf.org/html/rfc2324#section-2.3
+ * @see https://tools.ietf.org/html/rfc2518#section-9.7
+ * @see https://tools.ietf.org/html/rfc2774#section-7
+ * @see https://tools.ietf.org/html/rfc3229#section-10.4
+ * @see https://tools.ietf.org/html/rfc4918#section-11
+ * @see https://tools.ietf.org/html/rfc5842#section-7.1
+ * @see https://tools.ietf.org/html/rfc5842#section-7.2
+ * @see https://tools.ietf.org/html/rfc6585#section-3
+ * @see https://tools.ietf.org/html/rfc6585#section-4
+ * @see https://tools.ietf.org/html/rfc6585#section-5
+ * @see https://tools.ietf.org/html/rfc6585#section-6
+ * @see https://tools.ietf.org/html/rfc7231#section-6
+ * @see https://tools.ietf.org/html/rfc7238#section-3
+ * @see https://tools.ietf.org/html/rfc7725#section-3
+ * @see https://tools.ietf.org/html/rfc7540#section-9.1.2
+ * @see https://tools.ietf.org/html/rfc8297#section-2
+ * @see https://tools.ietf.org/html/rfc8470#section-7
+ * Usage:
+ *
+ * <code>
+ * class ResponseFactory implements StatusCodeInterface
+ * {
+ * public function createResponse($code = self::STATUS_OK)
+ * {
+ * }
+ * }
+ * </code>
+ */
+interface StatusCodeInterface
+{
+ // Informational 1xx
+ const STATUS_CONTINUE = 100;
+ const STATUS_SWITCHING_PROTOCOLS = 101;
+ const STATUS_PROCESSING = 102;
+ const STATUS_EARLY_HINTS = 103;
+ // Successful 2xx
+ const STATUS_OK = 200;
+ const STATUS_CREATED = 201;
+ const STATUS_ACCEPTED = 202;
+ const STATUS_NON_AUTHORITATIVE_INFORMATION = 203;
+ const STATUS_NO_CONTENT = 204;
+ const STATUS_RESET_CONTENT = 205;
+ const STATUS_PARTIAL_CONTENT = 206;
+ const STATUS_MULTI_STATUS = 207;
+ const STATUS_ALREADY_REPORTED = 208;
+ const STATUS_IM_USED = 226;
+ // Redirection 3xx
+ const STATUS_MULTIPLE_CHOICES = 300;
+ const STATUS_MOVED_PERMANENTLY = 301;
+ const STATUS_FOUND = 302;
+ const STATUS_SEE_OTHER = 303;
+ const STATUS_NOT_MODIFIED = 304;
+ const STATUS_USE_PROXY = 305;
+ const STATUS_RESERVED = 306;
+ const STATUS_TEMPORARY_REDIRECT = 307;
+ const STATUS_PERMANENT_REDIRECT = 308;
+ // Client Errors 4xx
+ const STATUS_BAD_REQUEST = 400;
+ const STATUS_UNAUTHORIZED = 401;
+ const STATUS_PAYMENT_REQUIRED = 402;
+ const STATUS_FORBIDDEN = 403;
+ const STATUS_NOT_FOUND = 404;
+ const STATUS_METHOD_NOT_ALLOWED = 405;
+ const STATUS_NOT_ACCEPTABLE = 406;
+ const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407;
+ const STATUS_REQUEST_TIMEOUT = 408;
+ const STATUS_CONFLICT = 409;
+ const STATUS_GONE = 410;
+ const STATUS_LENGTH_REQUIRED = 411;
+ const STATUS_PRECONDITION_FAILED = 412;
+ const STATUS_PAYLOAD_TOO_LARGE = 413;
+ const STATUS_URI_TOO_LONG = 414;
+ const STATUS_UNSUPPORTED_MEDIA_TYPE = 415;
+ const STATUS_RANGE_NOT_SATISFIABLE = 416;
+ const STATUS_EXPECTATION_FAILED = 417;
+ const STATUS_IM_A_TEAPOT = 418;
+ const STATUS_MISDIRECTED_REQUEST = 421;
+ const STATUS_UNPROCESSABLE_ENTITY = 422;
+ const STATUS_LOCKED = 423;
+ const STATUS_FAILED_DEPENDENCY = 424;
+ const STATUS_TOO_EARLY = 425;
+ const STATUS_UPGRADE_REQUIRED = 426;
+ const STATUS_PRECONDITION_REQUIRED = 428;
+ const STATUS_TOO_MANY_REQUESTS = 429;
+ const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
+ const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
+ // Server Errors 5xx
+ const STATUS_INTERNAL_SERVER_ERROR = 500;
+ const STATUS_NOT_IMPLEMENTED = 501;
+ const STATUS_BAD_GATEWAY = 502;
+ const STATUS_SERVICE_UNAVAILABLE = 503;
+ const STATUS_GATEWAY_TIMEOUT = 504;
+ const STATUS_VERSION_NOT_SUPPORTED = 505;
+ const STATUS_VARIANT_ALSO_NEGOTIATES = 506;
+ const STATUS_INSUFFICIENT_STORAGE = 507;
+ const STATUS_LOOP_DETECTED = 508;
+ const STATUS_NOT_EXTENDED = 510;
+ const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511;
+}
diff --git a/vendor/guzzlehttp/guzzle/LICENSE b/vendor/guzzlehttp/guzzle/LICENSE
new file mode 100644
index 0000000..fd2375d
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/LICENSE
@@ -0,0 +1,27 @@
+The MIT License (MIT)
+
+Copyright (c) 2011 Michael Dowling <mtdowling@gmail.com>
+Copyright (c) 2012 Jeremy Lindblom <jeremeamia@gmail.com>
+Copyright (c) 2014 Graham Campbell <hello@gjcampbell.co.uk>
+Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>
+Copyright (c) 2015 Tobias Schultze <webmaster@tubo-world.de>
+Copyright (c) 2016 Tobias Nyholm <tobias.nyholm@gmail.com>
+Copyright (c) 2016 George Mponos <gmponos@gmail.com>
+
+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/guzzlehttp/guzzle/composer.json b/vendor/guzzlehttp/guzzle/composer.json
new file mode 100644
index 0000000..b9cb386
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/composer.json
@@ -0,0 +1,89 @@
+{
+ "name": "guzzlehttp/guzzle",
+ "type": "library",
+ "description": "Guzzle is a PHP HTTP client library",
+ "keywords": [
+ "framework",
+ "http",
+ "rest",
+ "web service",
+ "curl",
+ "client",
+ "HTTP client"
+ ],
+ "homepage": "http://guzzlephp.org/",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "require": {
+ "php": ">=5.5",
+ "ext-json": "*",
+ "symfony/polyfill-intl-idn": "^1.17.0",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.5-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GuzzleHttp\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Client.php b/vendor/guzzlehttp/guzzle/src/Client.php
new file mode 100644
index 0000000..315a022
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Client.php
@@ -0,0 +1,501 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Cookie\CookieJar;
+use GuzzleHttp\Exception\GuzzleException;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
+ * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
+ * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
+ * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
+ * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
+ * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
+ * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
+ */
+class Client implements ClientInterface
+{
+ /** @var array Default request options */
+ private $config;
+
+ /**
+ * Clients accept an array of constructor parameters.
+ *
+ * Here's an example of creating a client using a base_uri and an array of
+ * default request options to apply to each request:
+ *
+ * $client = new Client([
+ * 'base_uri' => 'http://www.foo.com/1.0/',
+ * 'timeout' => 0,
+ * 'allow_redirects' => false,
+ * 'proxy' => '192.168.16.1:10'
+ * ]);
+ *
+ * Client configuration settings include the following options:
+ *
+ * - handler: (callable) Function that transfers HTTP requests over the
+ * wire. The function is called with a Psr7\Http\Message\RequestInterface
+ * and array of transfer options, and must return a
+ * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
+ * Psr7\Http\Message\ResponseInterface on success.
+ * If no handler is provided, a default handler will be created
+ * that enables all of the request options below by attaching all of the
+ * default middleware to the handler.
+ * - base_uri: (string|UriInterface) Base URI of the client that is merged
+ * into relative URIs. Can be a string or instance of UriInterface.
+ * - **: any request option
+ *
+ * @param array $config Client configuration settings.
+ *
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
+ */
+ public function __construct(array $config = [])
+ {
+ if (!isset($config['handler'])) {
+ $config['handler'] = HandlerStack::create();
+ } elseif (!is_callable($config['handler'])) {
+ throw new \InvalidArgumentException('handler must be a callable');
+ }
+
+ // Convert the base_uri to a UriInterface
+ if (isset($config['base_uri'])) {
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
+ }
+
+ $this->configureDefaults($config);
+ }
+
+ /**
+ * @param string $method
+ * @param array $args
+ *
+ * @return Promise\PromiseInterface
+ */
+ public function __call($method, $args)
+ {
+ if (count($args) < 1) {
+ throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
+ }
+
+ $uri = $args[0];
+ $opts = isset($args[1]) ? $args[1] : [];
+
+ return substr($method, -5) === 'Async'
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
+ : $this->request($method, $uri, $opts);
+ }
+
+ /**
+ * Asynchronously send an HTTP request.
+ *
+ * @param array $options Request options to apply to the given
+ * request and to the transfer. See \GuzzleHttp\RequestOptions.
+ *
+ * @return Promise\PromiseInterface
+ */
+ public function sendAsync(RequestInterface $request, array $options = [])
+ {
+ // Merge the base URI into the request URI if needed.
+ $options = $this->prepareDefaults($options);
+
+ return $this->transfer(
+ $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
+ $options
+ );
+ }
+
+ /**
+ * Send an HTTP request.
+ *
+ * @param array $options Request options to apply to the given
+ * request and to the transfer. See \GuzzleHttp\RequestOptions.
+ *
+ * @return ResponseInterface
+ * @throws GuzzleException
+ */
+ public function send(RequestInterface $request, array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->sendAsync($request, $options)->wait();
+ }
+
+ /**
+ * Create and send an asynchronous HTTP request.
+ *
+ * Use an absolute path to override the base path of the client, or a
+ * relative path to append to the base path of the client. The URL can
+ * contain the query string as well. Use an array to provide a URL
+ * template and additional variables to use in the URL template expansion.
+ *
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI object or string.
+ * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
+ *
+ * @return Promise\PromiseInterface
+ */
+ public function requestAsync($method, $uri = '', array $options = [])
+ {
+ $options = $this->prepareDefaults($options);
+ // Remove request modifying parameter because it can be done up-front.
+ $headers = isset($options['headers']) ? $options['headers'] : [];
+ $body = isset($options['body']) ? $options['body'] : null;
+ $version = isset($options['version']) ? $options['version'] : '1.1';
+ // Merge the URI into the base URI.
+ $uri = $this->buildUri($uri, $options);
+ if (is_array($body)) {
+ $this->invalidBody();
+ }
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
+ // Remove the option so that they are not doubly-applied.
+ unset($options['headers'], $options['body'], $options['version']);
+
+ return $this->transfer($request, $options);
+ }
+
+ /**
+ * Create and send an HTTP request.
+ *
+ * Use an absolute path to override the base path of the client, or a
+ * relative path to append to the base path of the client. The URL can
+ * contain the query string as well.
+ *
+ * @param string $method HTTP method.
+ * @param string|UriInterface $uri URI object or string.
+ * @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
+ *
+ * @return ResponseInterface
+ * @throws GuzzleException
+ */
+ public function request($method, $uri = '', array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->requestAsync($method, $uri, $options)->wait();
+ }
+
+ /**
+ * Get a client configuration option.
+ *
+ * These options include default request options of the client, a "handler"
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
+ * the concrete client.
+ *
+ * @param string|null $option The config option to retrieve.
+ *
+ * @return mixed
+ */
+ public function getConfig($option = null)
+ {
+ return $option === null
+ ? $this->config
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
+ }
+
+ /**
+ * @param string|null $uri
+ *
+ * @return UriInterface
+ */
+ private function buildUri($uri, array $config)
+ {
+ // for BC we accept null which would otherwise fail in uri_for
+ $uri = Psr7\uri_for($uri === null ? '' : $uri);
+
+ if (isset($config['base_uri'])) {
+ $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
+ }
+
+ if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
+ $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
+ $uri = Utils::idnUriConvert($uri, $idnOptions);
+ }
+
+ return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
+ }
+
+ /**
+ * Configures the default options for a client.
+ *
+ * @param array $config
+ * @return void
+ */
+ private function configureDefaults(array $config)
+ {
+ $defaults = [
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
+ 'http_errors' => true,
+ 'decode_content' => true,
+ 'verify' => true,
+ 'cookies' => false,
+ 'idn_conversion' => true,
+ ];
+
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
+
+ // We can only trust the HTTP_PROXY environment variable in a CLI
+ // process due to the fact that PHP has no reliable mechanism to
+ // get environment variables that start with "HTTP_".
+ if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
+ $defaults['proxy']['http'] = getenv('HTTP_PROXY');
+ }
+
+ if ($proxy = getenv('HTTPS_PROXY')) {
+ $defaults['proxy']['https'] = $proxy;
+ }
+
+ if ($noProxy = getenv('NO_PROXY')) {
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
+ }
+
+ $this->config = $config + $defaults;
+
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
+ $this->config['cookies'] = new CookieJar();
+ }
+
+ // Add the default user-agent header.
+ if (!isset($this->config['headers'])) {
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
+ } else {
+ // Add the User-Agent header if one was not already set.
+ foreach (array_keys($this->config['headers']) as $name) {
+ if (strtolower($name) === 'user-agent') {
+ return;
+ }
+ }
+ $this->config['headers']['User-Agent'] = default_user_agent();
+ }
+ }
+
+ /**
+ * Merges default options into the array.
+ *
+ * @param array $options Options to modify by reference
+ *
+ * @return array
+ */
+ private function prepareDefaults(array $options)
+ {
+ $defaults = $this->config;
+
+ if (!empty($defaults['headers'])) {
+ // Default headers are only added if they are not present.
+ $defaults['_conditional'] = $defaults['headers'];
+ unset($defaults['headers']);
+ }
+
+ // Special handling for headers is required as they are added as
+ // conditional headers and as headers passed to a request ctor.
+ if (array_key_exists('headers', $options)) {
+ // Allows default headers to be unset.
+ if ($options['headers'] === null) {
+ $defaults['_conditional'] = [];
+ unset($options['headers']);
+ } elseif (!is_array($options['headers'])) {
+ throw new \InvalidArgumentException('headers must be an array');
+ }
+ }
+
+ // Shallow merge defaults underneath options.
+ $result = $options + $defaults;
+
+ // Remove null values.
+ foreach ($result as $k => $v) {
+ if ($v === null) {
+ unset($result[$k]);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Transfers the given request and applies request options.
+ *
+ * The URI of the request is not modified and the request options are used
+ * as-is without merging in default options.
+ *
+ * @param array $options See \GuzzleHttp\RequestOptions.
+ *
+ * @return Promise\PromiseInterface
+ */
+ private function transfer(RequestInterface $request, array $options)
+ {
+ // save_to -> sink
+ if (isset($options['save_to'])) {
+ $options['sink'] = $options['save_to'];
+ unset($options['save_to']);
+ }
+
+ // exceptions -> http_errors
+ if (isset($options['exceptions'])) {
+ $options['http_errors'] = $options['exceptions'];
+ unset($options['exceptions']);
+ }
+
+ $request = $this->applyOptions($request, $options);
+ /** @var HandlerStack $handler */
+ $handler = $options['handler'];
+
+ try {
+ return Promise\promise_for($handler($request, $options));
+ } catch (\Exception $e) {
+ return Promise\rejection_for($e);
+ }
+ }
+
+ /**
+ * Applies the array of request options to a request.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return RequestInterface
+ */
+ private function applyOptions(RequestInterface $request, array &$options)
+ {
+ $modify = [
+ 'set_headers' => [],
+ ];
+
+ if (isset($options['headers'])) {
+ $modify['set_headers'] = $options['headers'];
+ unset($options['headers']);
+ }
+
+ if (isset($options['form_params'])) {
+ if (isset($options['multipart'])) {
+ throw new \InvalidArgumentException('You cannot use '
+ . 'form_params and multipart at the same time. Use the '
+ . 'form_params option if you want to send application/'
+ . 'x-www-form-urlencoded requests, and the multipart '
+ . 'option to send multipart/form-data requests.');
+ }
+ $options['body'] = http_build_query($options['form_params'], '', '&');
+ unset($options['form_params']);
+ // Ensure that we don't have the header in different case and set the new value.
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+
+ if (isset($options['multipart'])) {
+ $options['body'] = new Psr7\MultipartStream($options['multipart']);
+ unset($options['multipart']);
+ }
+
+ if (isset($options['json'])) {
+ $options['body'] = \GuzzleHttp\json_encode($options['json']);
+ unset($options['json']);
+ // Ensure that we don't have the header in different case and set the new value.
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
+ $options['_conditional']['Content-Type'] = 'application/json';
+ }
+
+ if (!empty($options['decode_content'])
+ && $options['decode_content'] !== true
+ ) {
+ // Ensure that we don't have the header in different case and set the new value.
+ $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
+ }
+
+ if (isset($options['body'])) {
+ if (is_array($options['body'])) {
+ $this->invalidBody();
+ }
+ $modify['body'] = Psr7\stream_for($options['body']);
+ unset($options['body']);
+ }
+
+ if (!empty($options['auth']) && is_array($options['auth'])) {
+ $value = $options['auth'];
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
+ switch ($type) {
+ case 'basic':
+ // Ensure that we don't have the header in different case and set the new value.
+ $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
+ $modify['set_headers']['Authorization'] = 'Basic '
+ . base64_encode("$value[0]:$value[1]");
+ break;
+ case 'digest':
+ // @todo: Do not rely on curl
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
+ break;
+ case 'ntlm':
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
+ break;
+ }
+ }
+
+ if (isset($options['query'])) {
+ $value = $options['query'];
+ if (is_array($value)) {
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
+ }
+ if (!is_string($value)) {
+ throw new \InvalidArgumentException('query must be a string or array');
+ }
+ $modify['query'] = $value;
+ unset($options['query']);
+ }
+
+ // Ensure that sink is not an invalid value.
+ if (isset($options['sink'])) {
+ // TODO: Add more sink validation?
+ if (is_bool($options['sink'])) {
+ throw new \InvalidArgumentException('sink must not be a boolean');
+ }
+ }
+
+ $request = Psr7\modify_request($request, $modify);
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
+ // Use a multipart/form-data POST if a Content-Type is not set.
+ // Ensure that we don't have the header in different case and set the new value.
+ $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
+ . $request->getBody()->getBoundary();
+ }
+
+ // Merge in conditional headers if they are not present.
+ if (isset($options['_conditional'])) {
+ // Build up the changes so it's in a single clone of the message.
+ $modify = [];
+ foreach ($options['_conditional'] as $k => $v) {
+ if (!$request->hasHeader($k)) {
+ $modify['set_headers'][$k] = $v;
+ }
+ }
+ $request = Psr7\modify_request($request, $modify);
+ // Don't pass this internal value along to middleware/handlers.
+ unset($options['_conditional']);
+ }
+
+ return $request;
+ }
+
+ /**
+ * Throw Exception with pre-set message.
+ * @return void
+ * @throws \InvalidArgumentException Invalid body.
+ */
+ private function invalidBody()
+ {
+ throw new \InvalidArgumentException('Passing in the "body" request '
+ . 'option as an array to send a POST request has been deprecated. '
+ . 'Please use the "form_params" request option to send a '
+ . 'application/x-www-form-urlencoded request, or the "multipart" '
+ . 'request option to send a multipart/form-data request.');
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/vendor/guzzlehttp/guzzle/src/ClientInterface.php
new file mode 100644
index 0000000..638b75d
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/ClientInterface.php
@@ -0,0 +1,87 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Exception\GuzzleException;
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Client interface for sending HTTP requests.
+ */
+interface ClientInterface
+{
+ /**
+ * @deprecated Will be removed in Guzzle 7.0.0
+ */
+ const VERSION = '6.5.5';
+
+ /**
+ * Send an HTTP request.
+ *
+ * @param RequestInterface $request Request to send
+ * @param array $options Request options to apply to the given
+ * request and to the transfer.
+ *
+ * @return ResponseInterface
+ * @throws GuzzleException
+ */
+ public function send(RequestInterface $request, array $options = []);
+
+ /**
+ * Asynchronously send an HTTP request.
+ *
+ * @param RequestInterface $request Request to send
+ * @param array $options Request options to apply to the given
+ * request and to the transfer.
+ *
+ * @return PromiseInterface
+ */
+ public function sendAsync(RequestInterface $request, array $options = []);
+
+ /**
+ * Create and send an HTTP request.
+ *
+ * Use an absolute path to override the base path of the client, or a
+ * relative path to append to the base path of the client. The URL can
+ * contain the query string as well.
+ *
+ * @param string $method HTTP method.
+ * @param string|UriInterface $uri URI object or string.
+ * @param array $options Request options to apply.
+ *
+ * @return ResponseInterface
+ * @throws GuzzleException
+ */
+ public function request($method, $uri, array $options = []);
+
+ /**
+ * Create and send an asynchronous HTTP request.
+ *
+ * Use an absolute path to override the base path of the client, or a
+ * relative path to append to the base path of the client. The URL can
+ * contain the query string as well. Use an array to provide a URL
+ * template and additional variables to use in the URL template expansion.
+ *
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI object or string.
+ * @param array $options Request options to apply.
+ *
+ * @return PromiseInterface
+ */
+ public function requestAsync($method, $uri, array $options = []);
+
+ /**
+ * Get a client configuration option.
+ *
+ * These options include default request options of the client, a "handler"
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
+ * the concrete client.
+ *
+ * @param string|null $option The config option to retrieve.
+ *
+ * @return mixed
+ */
+ public function getConfig($option = null);
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
new file mode 100644
index 0000000..394df3a
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
@@ -0,0 +1,321 @@
+<?php
+namespace GuzzleHttp\Cookie;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Cookie jar that stores cookies as an array
+ */
+class CookieJar implements CookieJarInterface
+{
+ /** @var SetCookie[] Loaded cookie data */
+ private $cookies = [];
+
+ /** @var bool */
+ private $strictMode;
+
+ /**
+ * @param bool $strictMode Set to true to throw exceptions when invalid
+ * cookies are added to the cookie jar.
+ * @param array $cookieArray Array of SetCookie objects or a hash of
+ * arrays that can be used with the SetCookie
+ * constructor
+ */
+ public function __construct($strictMode = false, $cookieArray = [])
+ {
+ $this->strictMode = $strictMode;
+
+ foreach ($cookieArray as $cookie) {
+ if (!($cookie instanceof SetCookie)) {
+ $cookie = new SetCookie($cookie);
+ }
+ $this->setCookie($cookie);
+ }
+ }
+
+ /**
+ * Create a new Cookie jar from an associative array and domain.
+ *
+ * @param array $cookies Cookies to create the jar from
+ * @param string $domain Domain to set the cookies to
+ *
+ * @return self
+ */
+ public static function fromArray(array $cookies, $domain)
+ {
+ $cookieJar = new self();
+ foreach ($cookies as $name => $value) {
+ $cookieJar->setCookie(new SetCookie([
+ 'Domain' => $domain,
+ 'Name' => $name,
+ 'Value' => $value,
+ 'Discard' => true
+ ]));
+ }
+
+ return $cookieJar;
+ }
+
+ /**
+ * @deprecated
+ */
+ public static function getCookieValue($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Evaluate if this cookie should be persisted to storage
+ * that survives between requests.
+ *
+ * @param SetCookie $cookie Being evaluated.
+ * @param bool $allowSessionCookies If we should persist session cookies
+ * @return bool
+ */
+ public static function shouldPersist(
+ SetCookie $cookie,
+ $allowSessionCookies = false
+ ) {
+ if ($cookie->getExpires() || $allowSessionCookies) {
+ if (!$cookie->getDiscard()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Finds and returns the cookie based on the name
+ *
+ * @param string $name cookie name to search for
+ * @return SetCookie|null cookie that was found or null if not found
+ */
+ public function getCookieByName($name)
+ {
+ // don't allow a non string name
+ if ($name === null || !is_scalar($name)) {
+ return null;
+ }
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
+ return $cookie;
+ }
+ }
+
+ return null;
+ }
+
+ public function toArray()
+ {
+ return array_map(function (SetCookie $cookie) {
+ return $cookie->toArray();
+ }, $this->getIterator()->getArrayCopy());
+ }
+
+ public function clear($domain = null, $path = null, $name = null)
+ {
+ if (!$domain) {
+ $this->cookies = [];
+ return;
+ } elseif (!$path) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($domain) {
+ return !$cookie->matchesDomain($domain);
+ }
+ );
+ } elseif (!$name) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ } else {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain, $name) {
+ return !($cookie->getName() == $name &&
+ $cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ }
+ }
+
+ public function clearSessionCookies()
+ {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) {
+ return !$cookie->getDiscard() && $cookie->getExpires();
+ }
+ );
+ }
+
+ public function setCookie(SetCookie $cookie)
+ {
+ // If the name string is empty (but not 0), ignore the set-cookie
+ // string entirely.
+ $name = $cookie->getName();
+ if (!$name && $name !== '0') {
+ return false;
+ }
+
+ // Only allow cookies with set and valid domain, name, value
+ $result = $cookie->validate();
+ if ($result !== true) {
+ if ($this->strictMode) {
+ throw new \RuntimeException('Invalid cookie: ' . $result);
+ } else {
+ $this->removeCookieIfEmpty($cookie);
+ return false;
+ }
+ }
+
+ // Resolve conflicts with previously set cookies
+ foreach ($this->cookies as $i => $c) {
+
+ // Two cookies are identical, when their path, and domain are
+ // identical.
+ if ($c->getPath() != $cookie->getPath() ||
+ $c->getDomain() != $cookie->getDomain() ||
+ $c->getName() != $cookie->getName()
+ ) {
+ continue;
+ }
+
+ // The previously set cookie is a discard cookie and this one is
+ // not so allow the new cookie to be set
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the new cookie's expiration is further into the future, then
+ // replace the old cookie
+ if ($cookie->getExpires() > $c->getExpires()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the value has changed, we better change it
+ if ($cookie->getValue() !== $c->getValue()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // The cookie exists, so no need to continue
+ return false;
+ }
+
+ $this->cookies[] = $cookie;
+
+ return true;
+ }
+
+ public function count()
+ {
+ return count($this->cookies);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator(array_values($this->cookies));
+ }
+
+ public function extractCookies(
+ RequestInterface $request,
+ ResponseInterface $response
+ ) {
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
+ foreach ($cookieHeader as $cookie) {
+ $sc = SetCookie::fromString($cookie);
+ if (!$sc->getDomain()) {
+ $sc->setDomain($request->getUri()->getHost());
+ }
+ if (0 !== strpos($sc->getPath(), '/')) {
+ $sc->setPath($this->getCookiePathFromRequest($request));
+ }
+ if (!$sc->matchesDomain($request->getUri()->getHost())) {
+ continue;
+ }
+ // Note: At this point `$sc->getDomain()` being a public suffix should
+ // be rejected, but we don't want to pull in the full PSL dependency.
+ $this->setCookie($sc);
+ }
+ }
+ }
+
+ /**
+ * Computes cookie path following RFC 6265 section 5.1.4
+ *
+ * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
+ *
+ * @param RequestInterface $request
+ * @return string
+ */
+ private function getCookiePathFromRequest(RequestInterface $request)
+ {
+ $uriPath = $request->getUri()->getPath();
+ if ('' === $uriPath) {
+ return '/';
+ }
+ if (0 !== strpos($uriPath, '/')) {
+ return '/';
+ }
+ if ('/' === $uriPath) {
+ return '/';
+ }
+ if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
+ return '/';
+ }
+
+ return substr($uriPath, 0, $lastSlashPos);
+ }
+
+ public function withCookieHeader(RequestInterface $request)
+ {
+ $values = [];
+ $uri = $request->getUri();
+ $scheme = $uri->getScheme();
+ $host = $uri->getHost();
+ $path = $uri->getPath() ?: '/';
+
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($host) &&
+ !$cookie->isExpired() &&
+ (!$cookie->getSecure() || $scheme === 'https')
+ ) {
+ $values[] = $cookie->getName() . '='
+ . $cookie->getValue();
+ }
+ }
+
+ return $values
+ ? $request->withHeader('Cookie', implode('; ', $values))
+ : $request;
+ }
+
+ /**
+ * If a cookie already exists and the server asks to set it again with a
+ * null value, the cookie must be deleted.
+ *
+ * @param SetCookie $cookie
+ */
+ private function removeCookieIfEmpty(SetCookie $cookie)
+ {
+ $cookieValue = $cookie->getValue();
+ if ($cookieValue === null || $cookieValue === '') {
+ $this->clear(
+ $cookie->getDomain(),
+ $cookie->getPath(),
+ $cookie->getName()
+ );
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
new file mode 100644
index 0000000..6ee1188
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
@@ -0,0 +1,84 @@
+<?php
+namespace GuzzleHttp\Cookie;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Stores HTTP cookies.
+ *
+ * It extracts cookies from HTTP requests, and returns them in HTTP responses.
+ * CookieJarInterface instances automatically expire contained cookies when
+ * necessary. Subclasses are also responsible for storing and retrieving
+ * cookies from a file, database, etc.
+ *
+ * @link http://docs.python.org/2/library/cookielib.html Inspiration
+ */
+interface CookieJarInterface extends \Countable, \IteratorAggregate
+{
+ /**
+ * Create a request with added cookie headers.
+ *
+ * If no matching cookies are found in the cookie jar, then no Cookie
+ * header is added to the request and the same request is returned.
+ *
+ * @param RequestInterface $request Request object to modify.
+ *
+ * @return RequestInterface returns the modified request.
+ */
+ public function withCookieHeader(RequestInterface $request);
+
+ /**
+ * Extract cookies from an HTTP response and store them in the CookieJar.
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param ResponseInterface $response Response that was received
+ */
+ public function extractCookies(
+ RequestInterface $request,
+ ResponseInterface $response
+ );
+
+ /**
+ * Sets a cookie in the cookie jar.
+ *
+ * @param SetCookie $cookie Cookie to set.
+ *
+ * @return bool Returns true on success or false on failure
+ */
+ public function setCookie(SetCookie $cookie);
+
+ /**
+ * Remove cookies currently held in the cookie jar.
+ *
+ * Invoking this method without arguments will empty the whole cookie jar.
+ * If given a $domain argument only cookies belonging to that domain will
+ * be removed. If given a $domain and $path argument, cookies belonging to
+ * the specified path within that domain are removed. If given all three
+ * arguments, then the cookie with the specified name, path and domain is
+ * removed.
+ *
+ * @param string|null $domain Clears cookies matching a domain
+ * @param string|null $path Clears cookies matching a domain and path
+ * @param string|null $name Clears cookies matching a domain, path, and name
+ *
+ * @return CookieJarInterface
+ */
+ public function clear($domain = null, $path = null, $name = null);
+
+ /**
+ * Discard all sessions cookies.
+ *
+ * Removes cookies that don't have an expire field or a have a discard
+ * field set to true. To be called when the user agent shuts down according
+ * to RFC 2965.
+ */
+ public function clearSessionCookies();
+
+ /**
+ * Converts the cookie jar to an array.
+ *
+ * @return array
+ */
+ public function toArray();
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
new file mode 100644
index 0000000..3fb8600
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
@@ -0,0 +1,91 @@
+<?php
+namespace GuzzleHttp\Cookie;
+
+/**
+ * Persists non-session cookies using a JSON formatted file
+ */
+class FileCookieJar extends CookieJar
+{
+ /** @var string filename */
+ private $filename;
+
+ /** @var bool Control whether to persist session cookies or not. */
+ private $storeSessionCookies;
+
+ /**
+ * Create a new FileCookieJar object
+ *
+ * @param string $cookieFile File to store the cookie data
+ * @param bool $storeSessionCookies Set to true to store session cookies
+ * in the cookie jar.
+ *
+ * @throws \RuntimeException if the file cannot be found or created
+ */
+ public function __construct($cookieFile, $storeSessionCookies = false)
+ {
+ parent::__construct();
+ $this->filename = $cookieFile;
+ $this->storeSessionCookies = $storeSessionCookies;
+
+ if (file_exists($cookieFile)) {
+ $this->load($cookieFile);
+ }
+ }
+
+ /**
+ * Saves the file when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save($this->filename);
+ }
+
+ /**
+ * Saves the cookies to a file.
+ *
+ * @param string $filename File to save
+ * @throws \RuntimeException if the file cannot be found or created
+ */
+ public function save($filename)
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ /** @var SetCookie $cookie */
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ $jsonStr = \GuzzleHttp\json_encode($json);
+ if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
+ throw new \RuntimeException("Unable to save file {$filename}");
+ }
+ }
+
+ /**
+ * Load cookies from a JSON formatted file.
+ *
+ * Old cookies are kept unless overwritten by newly loaded ones.
+ *
+ * @param string $filename Cookie file to load.
+ * @throws \RuntimeException if the file cannot be loaded.
+ */
+ public function load($filename)
+ {
+ $json = file_get_contents($filename);
+ if (false === $json) {
+ throw new \RuntimeException("Unable to load file {$filename}");
+ } elseif ($json === '') {
+ return;
+ }
+
+ $data = \GuzzleHttp\json_decode($json, true);
+ if (is_array($data)) {
+ foreach (json_decode($json, true) as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
new file mode 100644
index 0000000..0224a24
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
@@ -0,0 +1,72 @@
+<?php
+namespace GuzzleHttp\Cookie;
+
+/**
+ * Persists cookies in the client session
+ */
+class SessionCookieJar extends CookieJar
+{
+ /** @var string session key */
+ private $sessionKey;
+
+ /** @var bool Control whether to persist session cookies or not. */
+ private $storeSessionCookies;
+
+ /**
+ * Create a new SessionCookieJar object
+ *
+ * @param string $sessionKey Session key name to store the cookie
+ * data in session
+ * @param bool $storeSessionCookies Set to true to store session cookies
+ * in the cookie jar.
+ */
+ public function __construct($sessionKey, $storeSessionCookies = false)
+ {
+ parent::__construct();
+ $this->sessionKey = $sessionKey;
+ $this->storeSessionCookies = $storeSessionCookies;
+ $this->load();
+ }
+
+ /**
+ * Saves cookies to session when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save();
+ }
+
+ /**
+ * Save cookies to the client session
+ */
+ public function save()
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ /** @var SetCookie $cookie */
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ $_SESSION[$this->sessionKey] = json_encode($json);
+ }
+
+ /**
+ * Load the contents of the client session into the data array
+ */
+ protected function load()
+ {
+ if (!isset($_SESSION[$this->sessionKey])) {
+ return;
+ }
+ $data = json_decode($_SESSION[$this->sessionKey], true);
+ if (is_array($data)) {
+ foreach ($data as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie data");
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
new file mode 100644
index 0000000..55f6901
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
@@ -0,0 +1,410 @@
+<?php
+namespace GuzzleHttp\Cookie;
+
+/**
+ * Set-Cookie object
+ */
+class SetCookie
+{
+ /** @var array */
+ private static $defaults = [
+ 'Name' => null,
+ 'Value' => null,
+ 'Domain' => null,
+ 'Path' => '/',
+ 'Max-Age' => null,
+ 'Expires' => null,
+ 'Secure' => false,
+ 'Discard' => false,
+ 'HttpOnly' => false
+ ];
+
+ /** @var array Cookie data */
+ private $data;
+
+ /**
+ * Create a new SetCookie object from a string
+ *
+ * @param string $cookie Set-Cookie header string
+ *
+ * @return self
+ */
+ public static function fromString($cookie)
+ {
+ // Create the default return array
+ $data = self::$defaults;
+ // Explode the cookie string using a series of semicolons
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
+ // The name of the cookie (first kvp) must exist and include an equal sign.
+ if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
+ return new self($data);
+ }
+
+ // Add the cookie pieces into the parsed data array
+ foreach ($pieces as $part) {
+ $cookieParts = explode('=', $part, 2);
+ $key = trim($cookieParts[0]);
+ $value = isset($cookieParts[1])
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
+ : true;
+
+ // Only check for non-cookies when cookies have been found
+ if (empty($data['Name'])) {
+ $data['Name'] = $key;
+ $data['Value'] = $value;
+ } else {
+ foreach (array_keys(self::$defaults) as $search) {
+ if (!strcasecmp($search, $key)) {
+ $data[$search] = $value;
+ continue 2;
+ }
+ }
+ $data[$key] = $value;
+ }
+ }
+
+ return new self($data);
+ }
+
+ /**
+ * @param array $data Array of cookie data provided by a Cookie parser
+ */
+ public function __construct(array $data = [])
+ {
+ $this->data = array_replace(self::$defaults, $data);
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
+ if (!$this->getExpires() && $this->getMaxAge()) {
+ // Calculate the Expires date
+ $this->setExpires(time() + $this->getMaxAge());
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
+ $this->setExpires($this->getExpires());
+ }
+ }
+
+ public function __toString()
+ {
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
+ foreach ($this->data as $k => $v) {
+ if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
+ if ($k === 'Expires') {
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
+ } else {
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
+ }
+ }
+ }
+
+ return rtrim($str, '; ');
+ }
+
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Get the cookie name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->data['Name'];
+ }
+
+ /**
+ * Set the cookie name
+ *
+ * @param string $name Cookie name
+ */
+ public function setName($name)
+ {
+ $this->data['Name'] = $name;
+ }
+
+ /**
+ * Get the cookie value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->data['Value'];
+ }
+
+ /**
+ * Set the cookie value
+ *
+ * @param string $value Cookie value
+ */
+ public function setValue($value)
+ {
+ $this->data['Value'] = $value;
+ }
+
+ /**
+ * Get the domain
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->data['Domain'];
+ }
+
+ /**
+ * Set the domain of the cookie
+ *
+ * @param string $domain
+ */
+ public function setDomain($domain)
+ {
+ $this->data['Domain'] = $domain;
+ }
+
+ /**
+ * Get the path
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->data['Path'];
+ }
+
+ /**
+ * Set the path of the cookie
+ *
+ * @param string $path Path of the cookie
+ */
+ public function setPath($path)
+ {
+ $this->data['Path'] = $path;
+ }
+
+ /**
+ * Maximum lifetime of the cookie in seconds
+ *
+ * @return int|null
+ */
+ public function getMaxAge()
+ {
+ return $this->data['Max-Age'];
+ }
+
+ /**
+ * Set the max-age of the cookie
+ *
+ * @param int $maxAge Max age of the cookie in seconds
+ */
+ public function setMaxAge($maxAge)
+ {
+ $this->data['Max-Age'] = $maxAge;
+ }
+
+ /**
+ * The UNIX timestamp when the cookie Expires
+ *
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->data['Expires'];
+ }
+
+ /**
+ * Set the unix timestamp for which the cookie will expire
+ *
+ * @param int $timestamp Unix timestamp
+ */
+ public function setExpires($timestamp)
+ {
+ $this->data['Expires'] = is_numeric($timestamp)
+ ? (int) $timestamp
+ : strtotime($timestamp);
+ }
+
+ /**
+ * Get whether or not this is a secure cookie
+ *
+ * @return bool|null
+ */
+ public function getSecure()
+ {
+ return $this->data['Secure'];
+ }
+
+ /**
+ * Set whether or not the cookie is secure
+ *
+ * @param bool $secure Set to true or false if secure
+ */
+ public function setSecure($secure)
+ {
+ $this->data['Secure'] = $secure;
+ }
+
+ /**
+ * Get whether or not this is a session cookie
+ *
+ * @return bool|null
+ */
+ public function getDiscard()
+ {
+ return $this->data['Discard'];
+ }
+
+ /**
+ * Set whether or not this is a session cookie
+ *
+ * @param bool $discard Set to true or false if this is a session cookie
+ */
+ public function setDiscard($discard)
+ {
+ $this->data['Discard'] = $discard;
+ }
+
+ /**
+ * Get whether or not this is an HTTP only cookie
+ *
+ * @return bool
+ */
+ public function getHttpOnly()
+ {
+ return $this->data['HttpOnly'];
+ }
+
+ /**
+ * Set whether or not this is an HTTP only cookie
+ *
+ * @param bool $httpOnly Set to true or false if this is HTTP only
+ */
+ public function setHttpOnly($httpOnly)
+ {
+ $this->data['HttpOnly'] = $httpOnly;
+ }
+
+ /**
+ * Check if the cookie matches a path value.
+ *
+ * A request-path path-matches a given cookie-path if at least one of
+ * the following conditions holds:
+ *
+ * - The cookie-path and the request-path are identical.
+ * - The cookie-path is a prefix of the request-path, and the last
+ * character of the cookie-path is %x2F ("/").
+ * - The cookie-path is a prefix of the request-path, and the first
+ * character of the request-path that is not included in the cookie-
+ * path is a %x2F ("/") character.
+ *
+ * @param string $requestPath Path to check against
+ *
+ * @return bool
+ */
+ public function matchesPath($requestPath)
+ {
+ $cookiePath = $this->getPath();
+
+ // Match on exact matches or when path is the default empty "/"
+ if ($cookiePath === '/' || $cookiePath == $requestPath) {
+ return true;
+ }
+
+ // Ensure that the cookie-path is a prefix of the request path.
+ if (0 !== strpos($requestPath, $cookiePath)) {
+ return false;
+ }
+
+ // Match if the last character of the cookie-path is "/"
+ if (substr($cookiePath, -1, 1) === '/') {
+ return true;
+ }
+
+ // Match if the first character not included in cookie path is "/"
+ return substr($requestPath, strlen($cookiePath), 1) === '/';
+ }
+
+ /**
+ * Check if the cookie matches a domain value
+ *
+ * @param string $domain Domain to check against
+ *
+ * @return bool
+ */
+ public function matchesDomain($domain)
+ {
+ $cookieDomain = $this->getDomain();
+ if (null === $cookieDomain) {
+ return true;
+ }
+
+ // Remove the leading '.' as per spec in RFC 6265.
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
+ $cookieDomain = ltrim(strtolower($cookieDomain), '.');
+
+ $domain = strtolower($domain);
+
+ // Domain not set or exact match.
+ if ('' === $cookieDomain || $domain === $cookieDomain) {
+ return true;
+ }
+
+ // Matching the subdomain according to RFC 6265.
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
+ return false;
+ }
+
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
+ }
+
+ /**
+ * Check if the cookie is expired
+ *
+ * @return bool
+ */
+ public function isExpired()
+ {
+ return $this->getExpires() !== null && time() > $this->getExpires();
+ }
+
+ /**
+ * Check if the cookie is valid according to RFC 6265
+ *
+ * @return bool|string Returns true if valid or an error message if invalid
+ */
+ public function validate()
+ {
+ // Names must not be empty, but can be 0
+ $name = $this->getName();
+ if (empty($name) && !is_numeric($name)) {
+ return 'The cookie name must not be empty';
+ }
+
+ // Check if any of the invalid characters are present in the cookie name
+ if (preg_match(
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
+ $name
+ )) {
+ return 'Cookie name must not contain invalid characters: ASCII '
+ . 'Control characters (0-31;127), space, tab and the '
+ . 'following characters: ()<>@,;:\"/?={}';
+ }
+
+ // Value must not be empty, but can be 0
+ $value = $this->getValue();
+ if (empty($value) && !is_numeric($value)) {
+ return 'The cookie value must not be empty';
+ }
+
+ // Domains must not be empty, but can be 0
+ // A "0" is not a valid internet domain, but may be used as server name
+ // in a private network.
+ $domain = $this->getDomain();
+ if (empty($domain) && !is_numeric($domain)) {
+ return 'The cookie domain must not be empty';
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php b/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
new file mode 100644
index 0000000..427d896
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
@@ -0,0 +1,27 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Exception when an HTTP error occurs (4xx or 5xx error)
+ */
+class BadResponseException extends RequestException
+{
+ public function __construct(
+ $message,
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null,
+ array $handlerContext = []
+ ) {
+ if (null === $response) {
+ @trigger_error(
+ 'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
+ E_USER_DEPRECATED
+ );
+ }
+ parent::__construct($message, $request, $response, $previous, $handlerContext);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php b/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
new file mode 100644
index 0000000..4cfd393
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
@@ -0,0 +1,9 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+/**
+ * Exception when a client error is encountered (4xx codes)
+ */
+class ClientException extends BadResponseException
+{
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php b/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
new file mode 100644
index 0000000..d33b0cc
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
@@ -0,0 +1,37 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Exception thrown when a connection cannot be established.
+ *
+ * Note that no response is present for a ConnectException
+ */
+class ConnectException extends RequestException
+{
+ public function __construct(
+ $message,
+ RequestInterface $request,
+ \Exception $previous = null,
+ array $handlerContext = []
+ ) {
+ parent::__construct($message, $request, null, $previous, $handlerContext);
+ }
+
+ /**
+ * @return null
+ */
+ public function getResponse()
+ {
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return false;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php b/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
new file mode 100644
index 0000000..27b2722
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
@@ -0,0 +1,23 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+use Throwable;
+
+if (interface_exists(Throwable::class)) {
+ interface GuzzleException extends Throwable
+ {
+ }
+} else {
+ /**
+ * @method string getMessage()
+ * @method \Throwable|null getPrevious()
+ * @method mixed getCode()
+ * @method string getFile()
+ * @method int getLine()
+ * @method array getTrace()
+ * @method string getTraceAsString()
+ */
+ interface GuzzleException
+ {
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php b/vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..bfd20e2
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace GuzzleHttp\Exception;
+
+final class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException
+{
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php b/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
new file mode 100644
index 0000000..12dd081
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
@@ -0,0 +1,192 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * HTTP Request exception
+ */
+class RequestException extends TransferException
+{
+ /** @var RequestInterface */
+ private $request;
+
+ /** @var ResponseInterface|null */
+ private $response;
+
+ /** @var array */
+ private $handlerContext;
+
+ public function __construct(
+ $message,
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null,
+ array $handlerContext = []
+ ) {
+ // Set the code of the exception if the response is set and not future.
+ $code = $response && !($response instanceof PromiseInterface)
+ ? $response->getStatusCode()
+ : 0;
+ parent::__construct($message, $code, $previous);
+ $this->request = $request;
+ $this->response = $response;
+ $this->handlerContext = $handlerContext;
+ }
+
+ /**
+ * Wrap non-RequestExceptions with a RequestException
+ *
+ * @param RequestInterface $request
+ * @param \Exception $e
+ *
+ * @return RequestException
+ */
+ public static function wrapException(RequestInterface $request, \Exception $e)
+ {
+ return $e instanceof RequestException
+ ? $e
+ : new RequestException($e->getMessage(), $request, null, $e);
+ }
+
+ /**
+ * Factory method to create a new exception with a normalized error message
+ *
+ * @param RequestInterface $request Request
+ * @param ResponseInterface $response Response received
+ * @param \Exception $previous Previous exception
+ * @param array $ctx Optional handler context.
+ *
+ * @return self
+ */
+ public static function create(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null,
+ array $ctx = []
+ ) {
+ if (!$response) {
+ return new self(
+ 'Error completing request',
+ $request,
+ null,
+ $previous,
+ $ctx
+ );
+ }
+
+ $level = (int) floor($response->getStatusCode() / 100);
+ if ($level === 4) {
+ $label = 'Client error';
+ $className = ClientException::class;
+ } elseif ($level === 5) {
+ $label = 'Server error';
+ $className = ServerException::class;
+ } else {
+ $label = 'Unsuccessful request';
+ $className = __CLASS__;
+ }
+
+ $uri = $request->getUri();
+ $uri = static::obfuscateUri($uri);
+
+ // Client Error: `GET /` resulted in a `404 Not Found` response:
+ // <html> ... (truncated)
+ $message = sprintf(
+ '%s: `%s %s` resulted in a `%s %s` response',
+ $label,
+ $request->getMethod(),
+ $uri,
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ );
+
+ $summary = static::getResponseBodySummary($response);
+
+ if ($summary !== null) {
+ $message .= ":\n{$summary}\n";
+ }
+
+ return new $className($message, $request, $response, $previous, $ctx);
+ }
+
+ /**
+ * Get a short summary of the response
+ *
+ * Will return `null` if the response is not printable.
+ *
+ * @param ResponseInterface $response
+ *
+ * @return string|null
+ */
+ public static function getResponseBodySummary(ResponseInterface $response)
+ {
+ return \GuzzleHttp\Psr7\get_message_body_summary($response);
+ }
+
+ /**
+ * Obfuscates URI if there is a username and a password present
+ *
+ * @param UriInterface $uri
+ *
+ * @return UriInterface
+ */
+ private static function obfuscateUri(UriInterface $uri)
+ {
+ $userInfo = $uri->getUserInfo();
+
+ if (false !== ($pos = strpos($userInfo, ':'))) {
+ return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Get the request that caused the exception
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Get the associated response
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Check if a response was received
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Get contextual information about the error from the underlying handler.
+ *
+ * The contents of this array will vary depending on which handler you are
+ * using. It may also be just an empty array. Relying on this data will
+ * couple you to a specific handler, but can give more debug information
+ * when needed.
+ *
+ * @return array
+ */
+ public function getHandlerContext()
+ {
+ return $this->handlerContext;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php b/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
new file mode 100644
index 0000000..a77c289
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
@@ -0,0 +1,27 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Exception thrown when a seek fails on a stream.
+ */
+class SeekException extends \RuntimeException implements GuzzleException
+{
+ private $stream;
+
+ public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
+ {
+ $this->stream = $stream;
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
+ parent::__construct($msg);
+ }
+
+ /**
+ * @return StreamInterface
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php b/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
new file mode 100644
index 0000000..127094c
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
@@ -0,0 +1,9 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+/**
+ * Exception when a server error is encountered (5xx codes)
+ */
+class ServerException extends BadResponseException
+{
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php b/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
new file mode 100644
index 0000000..fff0525
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
@@ -0,0 +1,6 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+class TooManyRedirectsException extends RequestException
+{
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php b/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
new file mode 100644
index 0000000..7c11db3
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
@@ -0,0 +1,6 @@
+<?php
+namespace GuzzleHttp\Exception;
+
+class TransferException extends \RuntimeException implements GuzzleException
+{
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
new file mode 100644
index 0000000..4a28a96
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
@@ -0,0 +1,585 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise\FulfilledPromise;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\LazyOpenStream;
+use GuzzleHttp\TransferStats;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Creates curl resources from a request
+ */
+class CurlFactory implements CurlFactoryInterface
+{
+ const CURL_VERSION_STR = 'curl_version';
+ const LOW_CURL_VERSION_NUMBER = '7.21.2';
+
+ /** @var array */
+ private $handles = [];
+
+ /** @var int Total number of idle handles to keep in cache */
+ private $maxHandles;
+
+ /**
+ * @param int $maxHandles Maximum number of idle handles.
+ */
+ public function __construct($maxHandles)
+ {
+ $this->maxHandles = $maxHandles;
+ }
+
+ public function create(RequestInterface $request, array $options)
+ {
+ if (isset($options['curl']['body_as_string'])) {
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
+ unset($options['curl']['body_as_string']);
+ }
+
+ $easy = new EasyHandle;
+ $easy->request = $request;
+ $easy->options = $options;
+ $conf = $this->getDefaultConf($easy);
+ $this->applyMethod($easy, $conf);
+ $this->applyHandlerOptions($easy, $conf);
+ $this->applyHeaders($easy, $conf);
+ unset($conf['_headers']);
+
+ // Add handler options from the request configuration options
+ if (isset($options['curl'])) {
+ $conf = array_replace($conf, $options['curl']);
+ }
+
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
+ $easy->handle = $this->handles
+ ? array_pop($this->handles)
+ : curl_init();
+ curl_setopt_array($easy->handle, $conf);
+
+ return $easy;
+ }
+
+ public function release(EasyHandle $easy)
+ {
+ $resource = $easy->handle;
+ unset($easy->handle);
+
+ if (count($this->handles) >= $this->maxHandles) {
+ curl_close($resource);
+ } else {
+ // Remove all callback functions as they can hold onto references
+ // and are not cleaned up by curl_reset. Using curl_setopt_array
+ // does not work for some reason, so removing each one
+ // individually.
+ curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
+ curl_setopt($resource, CURLOPT_READFUNCTION, null);
+ curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
+ curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
+ curl_reset($resource);
+ $this->handles[] = $resource;
+ }
+ }
+
+ /**
+ * Completes a cURL transaction, either returning a response promise or a
+ * rejected promise.
+ *
+ * @param callable $handler
+ * @param EasyHandle $easy
+ * @param CurlFactoryInterface $factory Dictates how the handle is released
+ *
+ * @return \GuzzleHttp\Promise\PromiseInterface
+ */
+ public static function finish(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ if (isset($easy->options['on_stats'])) {
+ self::invokeStats($easy);
+ }
+
+ if (!$easy->response || $easy->errno) {
+ return self::finishError($handler, $easy, $factory);
+ }
+
+ // Return the response if it is present and there is no error.
+ $factory->release($easy);
+
+ // Rewind the body of the response if possible.
+ $body = $easy->response->getBody();
+ if ($body->isSeekable()) {
+ $body->rewind();
+ }
+
+ return new FulfilledPromise($easy->response);
+ }
+
+ private static function invokeStats(EasyHandle $easy)
+ {
+ $curlStats = curl_getinfo($easy->handle);
+ $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
+ $stats = new TransferStats(
+ $easy->request,
+ $easy->response,
+ $curlStats['total_time'],
+ $easy->errno,
+ $curlStats
+ );
+ call_user_func($easy->options['on_stats'], $stats);
+ }
+
+ private static function finishError(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ // Get error information and release the handle to the factory.
+ $ctx = [
+ 'errno' => $easy->errno,
+ 'error' => curl_error($easy->handle),
+ 'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME),
+ ] + curl_getinfo($easy->handle);
+ $ctx[self::CURL_VERSION_STR] = curl_version()['version'];
+ $factory->release($easy);
+
+ // Retry when nothing is present or when curl failed to rewind.
+ if (empty($easy->options['_err_message'])
+ && (!$easy->errno || $easy->errno == 65)
+ ) {
+ return self::retryFailedRewind($handler, $easy, $ctx);
+ }
+
+ return self::createRejection($easy, $ctx);
+ }
+
+ private static function createRejection(EasyHandle $easy, array $ctx)
+ {
+ static $connectionErrors = [
+ CURLE_OPERATION_TIMEOUTED => true,
+ CURLE_COULDNT_RESOLVE_HOST => true,
+ CURLE_COULDNT_CONNECT => true,
+ CURLE_SSL_CONNECT_ERROR => true,
+ CURLE_GOT_NOTHING => true,
+ ];
+
+ // If an exception was encountered during the onHeaders event, then
+ // return a rejected promise that wraps that exception.
+ if ($easy->onHeadersException) {
+ return \GuzzleHttp\Promise\rejection_for(
+ new RequestException(
+ 'An error was encountered during the on_headers event',
+ $easy->request,
+ $easy->response,
+ $easy->onHeadersException,
+ $ctx
+ )
+ );
+ }
+ if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {
+ $message = sprintf(
+ 'cURL error %s: %s (%s)',
+ $ctx['errno'],
+ $ctx['error'],
+ 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
+ );
+ } else {
+ $message = sprintf(
+ 'cURL error %s: %s (%s) for %s',
+ $ctx['errno'],
+ $ctx['error'],
+ 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',
+ $easy->request->getUri()
+ );
+ }
+
+ // Create a connection exception if it was a specific error code.
+ $error = isset($connectionErrors[$easy->errno])
+ ? new ConnectException($message, $easy->request, null, $ctx)
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
+
+ return \GuzzleHttp\Promise\rejection_for($error);
+ }
+
+ private function getDefaultConf(EasyHandle $easy)
+ {
+ $conf = [
+ '_headers' => $easy->request->getHeaders(),
+ CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
+ CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
+ CURLOPT_RETURNTRANSFER => false,
+ CURLOPT_HEADER => false,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ ];
+
+ if (defined('CURLOPT_PROTOCOLS')) {
+ $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+ }
+
+ $version = $easy->request->getProtocolVersion();
+ if ($version == 1.1) {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
+ } elseif ($version == 2.0) {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
+ } else {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
+ }
+
+ return $conf;
+ }
+
+ private function applyMethod(EasyHandle $easy, array &$conf)
+ {
+ $body = $easy->request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size > 0) {
+ $this->applyBody($easy->request, $easy->options, $conf);
+ return;
+ }
+
+ $method = $easy->request->getMethod();
+ if ($method === 'PUT' || $method === 'POST') {
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
+ if (!$easy->request->hasHeader('Content-Length')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
+ }
+ } elseif ($method === 'HEAD') {
+ $conf[CURLOPT_NOBODY] = true;
+ unset(
+ $conf[CURLOPT_WRITEFUNCTION],
+ $conf[CURLOPT_READFUNCTION],
+ $conf[CURLOPT_FILE],
+ $conf[CURLOPT_INFILE]
+ );
+ }
+ }
+
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
+ {
+ $size = $request->hasHeader('Content-Length')
+ ? (int) $request->getHeaderLine('Content-Length')
+ : null;
+
+ // Send the body as a string if the size is less than 1MB OR if the
+ // [curl][body_as_string] request value is set.
+ if (($size !== null && $size < 1000000) ||
+ !empty($options['_body_as_string'])
+ ) {
+ $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
+ // Don't duplicate the Content-Length header
+ $this->removeHeader('Content-Length', $conf);
+ $this->removeHeader('Transfer-Encoding', $conf);
+ } else {
+ $conf[CURLOPT_UPLOAD] = true;
+ if ($size !== null) {
+ $conf[CURLOPT_INFILESIZE] = $size;
+ $this->removeHeader('Content-Length', $conf);
+ }
+ $body = $request->getBody();
+ if ($body->isSeekable()) {
+ $body->rewind();
+ }
+ $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
+ return $body->read($length);
+ };
+ }
+
+ // If the Expect header is not present, prevent curl from adding it
+ if (!$request->hasHeader('Expect')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
+ }
+
+ // cURL sometimes adds a content-type by default. Prevent this.
+ if (!$request->hasHeader('Content-Type')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
+ }
+ }
+
+ private function applyHeaders(EasyHandle $easy, array &$conf)
+ {
+ foreach ($conf['_headers'] as $name => $values) {
+ foreach ($values as $value) {
+ $value = (string) $value;
+ if ($value === '') {
+ // cURL requires a special format for empty headers.
+ // See https://github.com/guzzle/guzzle/issues/1882 for more details.
+ $conf[CURLOPT_HTTPHEADER][] = "$name;";
+ } else {
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+ }
+ }
+ }
+
+ // Remove the Accept header if one was not set
+ if (!$easy->request->hasHeader('Accept')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
+ }
+ }
+
+ /**
+ * Remove a header from the options array.
+ *
+ * @param string $name Case-insensitive header to remove
+ * @param array $options Array of options to modify
+ */
+ private function removeHeader($name, array &$options)
+ {
+ foreach (array_keys($options['_headers']) as $key) {
+ if (!strcasecmp($key, $name)) {
+ unset($options['_headers'][$key]);
+ return;
+ }
+ }
+ }
+
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
+ {
+ $options = $easy->options;
+ if (isset($options['verify'])) {
+ if ($options['verify'] === false) {
+ unset($conf[CURLOPT_CAINFO]);
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
+ } else {
+ $conf[CURLOPT_SSL_VERIFYHOST] = 2;
+ $conf[CURLOPT_SSL_VERIFYPEER] = true;
+ if (is_string($options['verify'])) {
+ // Throw an error if the file/folder/link path is not valid or doesn't exist.
+ if (!file_exists($options['verify'])) {
+ throw new \InvalidArgumentException(
+ "SSL CA bundle not found: {$options['verify']}"
+ );
+ }
+ // If it's a directory or a link to a directory use CURLOPT_CAPATH.
+ // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
+ if (is_dir($options['verify']) ||
+ (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
+ $conf[CURLOPT_CAPATH] = $options['verify'];
+ } else {
+ $conf[CURLOPT_CAINFO] = $options['verify'];
+ }
+ }
+ }
+ }
+
+ if (!empty($options['decode_content'])) {
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
+ if ($accept) {
+ $conf[CURLOPT_ENCODING] = $accept;
+ } else {
+ $conf[CURLOPT_ENCODING] = '';
+ // Don't let curl send the header over the wire
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
+ }
+ }
+
+ if (isset($options['sink'])) {
+ $sink = $options['sink'];
+ if (!is_string($sink)) {
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
+ } elseif (!is_dir(dirname($sink))) {
+ // Ensure that the directory exists before failing in curl.
+ throw new \RuntimeException(sprintf(
+ 'Directory %s does not exist for sink value of %s',
+ dirname($sink),
+ $sink
+ ));
+ } else {
+ $sink = new LazyOpenStream($sink, 'w+');
+ }
+ $easy->sink = $sink;
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
+ return $sink->write($write);
+ };
+ } else {
+ // Use a default temp stream if no sink was set.
+ $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
+ $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
+ }
+ $timeoutRequiresNoSignal = false;
+ if (isset($options['timeout'])) {
+ $timeoutRequiresNoSignal |= $options['timeout'] < 1;
+ $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
+ }
+
+ // CURL default value is CURL_IPRESOLVE_WHATEVER
+ if (isset($options['force_ip_resolve'])) {
+ if ('v4' === $options['force_ip_resolve']) {
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
+ } elseif ('v6' === $options['force_ip_resolve']) {
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
+ }
+ }
+
+ if (isset($options['connect_timeout'])) {
+ $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
+ }
+
+ if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
+ $conf[CURLOPT_NOSIGNAL] = true;
+ }
+
+ if (isset($options['proxy'])) {
+ if (!is_array($options['proxy'])) {
+ $conf[CURLOPT_PROXY] = $options['proxy'];
+ } else {
+ $scheme = $easy->request->getUri()->getScheme();
+ if (isset($options['proxy'][$scheme])) {
+ $host = $easy->request->getUri()->getHost();
+ if (!isset($options['proxy']['no']) ||
+ !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
+ ) {
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
+ }
+ }
+ }
+ }
+
+ if (isset($options['cert'])) {
+ $cert = $options['cert'];
+ if (is_array($cert)) {
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
+ $cert = $cert[0];
+ }
+ if (!file_exists($cert)) {
+ throw new \InvalidArgumentException(
+ "SSL certificate not found: {$cert}"
+ );
+ }
+ $conf[CURLOPT_SSLCERT] = $cert;
+ }
+
+ if (isset($options['ssl_key'])) {
+ if (is_array($options['ssl_key'])) {
+ if (count($options['ssl_key']) === 2) {
+ list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
+ } else {
+ list($sslKey) = $options['ssl_key'];
+ }
+ }
+
+ $sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
+
+ if (!file_exists($sslKey)) {
+ throw new \InvalidArgumentException(
+ "SSL private key not found: {$sslKey}"
+ );
+ }
+ $conf[CURLOPT_SSLKEY] = $sslKey;
+ }
+
+ if (isset($options['progress'])) {
+ $progress = $options['progress'];
+ if (!is_callable($progress)) {
+ throw new \InvalidArgumentException(
+ 'progress client option must be callable'
+ );
+ }
+ $conf[CURLOPT_NOPROGRESS] = false;
+ $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
+ $args = func_get_args();
+ // PHP 5.5 pushed the handle onto the start of the args
+ if (is_resource($args[0])) {
+ array_shift($args);
+ }
+ call_user_func_array($progress, $args);
+ };
+ }
+
+ if (!empty($options['debug'])) {
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
+ $conf[CURLOPT_VERBOSE] = true;
+ }
+ }
+
+ /**
+ * This function ensures that a response was set on a transaction. If one
+ * was not set, then the request is retried if possible. This error
+ * typically means you are sending a payload, curl encountered a
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
+ * stream, and then encountered a "necessary data rewind wasn't possible"
+ * error, causing the request to be sent through curl_multi_info_read()
+ * without an error status.
+ */
+ private static function retryFailedRewind(
+ callable $handler,
+ EasyHandle $easy,
+ array $ctx
+ ) {
+ try {
+ // Only rewind if the body has been read from.
+ $body = $easy->request->getBody();
+ if ($body->tell() > 0) {
+ $body->rewind();
+ }
+ } catch (\RuntimeException $e) {
+ $ctx['error'] = 'The connection unexpectedly failed without '
+ . 'providing an error. The request would have been retried, '
+ . 'but attempting to rewind the request body failed. '
+ . 'Exception: ' . $e;
+ return self::createRejection($easy, $ctx);
+ }
+
+ // Retry no more than 3 times before giving up.
+ if (!isset($easy->options['_curl_retries'])) {
+ $easy->options['_curl_retries'] = 1;
+ } elseif ($easy->options['_curl_retries'] == 2) {
+ $ctx['error'] = 'The cURL request was retried 3 times '
+ . 'and did not succeed. The most likely reason for the failure '
+ . 'is that cURL was unable to rewind the body of the request '
+ . 'and subsequent retries resulted in the same error. Turn on '
+ . 'the debug option to see what went wrong. See '
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
+ return self::createRejection($easy, $ctx);
+ } else {
+ $easy->options['_curl_retries']++;
+ }
+
+ return $handler($easy->request, $easy->options);
+ }
+
+ private function createHeaderFn(EasyHandle $easy)
+ {
+ if (isset($easy->options['on_headers'])) {
+ $onHeaders = $easy->options['on_headers'];
+
+ if (!is_callable($onHeaders)) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+ } else {
+ $onHeaders = null;
+ }
+
+ return function ($ch, $h) use (
+ $onHeaders,
+ $easy,
+ &$startingResponse
+ ) {
+ $value = trim($h);
+ if ($value === '') {
+ $startingResponse = true;
+ $easy->createResponse();
+ if ($onHeaders !== null) {
+ try {
+ $onHeaders($easy->response);
+ } catch (\Exception $e) {
+ // Associate the exception with the handle and trigger
+ // a curl header write error by returning 0.
+ $easy->onHeadersException = $e;
+ return -1;
+ }
+ }
+ } elseif ($startingResponse) {
+ $startingResponse = false;
+ $easy->headers = [$value];
+ } else {
+ $easy->headers[] = $value;
+ }
+ return strlen($h);
+ };
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
new file mode 100644
index 0000000..b0fc236
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
@@ -0,0 +1,27 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use Psr\Http\Message\RequestInterface;
+
+interface CurlFactoryInterface
+{
+ /**
+ * Creates a cURL handle resource.
+ *
+ * @param RequestInterface $request Request
+ * @param array $options Transfer options
+ *
+ * @return EasyHandle
+ * @throws \RuntimeException when an option cannot be applied
+ */
+ public function create(RequestInterface $request, array $options);
+
+ /**
+ * Release an easy handle, allowing it to be reused or closed.
+ *
+ * This function must call unset on the easy handle's "handle" property.
+ *
+ * @param EasyHandle $easy
+ */
+ public function release(EasyHandle $easy);
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
new file mode 100644
index 0000000..43577da
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
@@ -0,0 +1,45 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * HTTP handler that uses cURL easy handles as a transport layer.
+ *
+ * When using the CurlHandler, custom curl options can be specified as an
+ * associative array of curl option constants mapping to values in the
+ * **curl** key of the "client" key of the request.
+ */
+class CurlHandler
+{
+ /** @var CurlFactoryInterface */
+ private $factory;
+
+ /**
+ * Accepts an associative array of options:
+ *
+ * - factory: Optional curl factory used to create cURL handles.
+ *
+ * @param array $options Array of options to use with the handler
+ */
+ public function __construct(array $options = [])
+ {
+ $this->factory = isset($options['handle_factory'])
+ ? $options['handle_factory']
+ : new CurlFactory(3);
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $easy = $this->factory->create($request, $options);
+ curl_exec($easy->handle);
+ $easy->errno = curl_errno($easy->handle);
+
+ return CurlFactory::finish($this, $easy, $this->factory);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
new file mode 100644
index 0000000..564c95f
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
@@ -0,0 +1,219 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Promise as P;
+use GuzzleHttp\Promise\Promise;
+use GuzzleHttp\Utils;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Returns an asynchronous response using curl_multi_* functions.
+ *
+ * When using the CurlMultiHandler, custom curl options can be specified as an
+ * associative array of curl option constants mapping to values in the
+ * **curl** key of the provided request options.
+ *
+ * @property resource $_mh Internal use only. Lazy loaded multi-handle.
+ */
+class CurlMultiHandler
+{
+ /** @var CurlFactoryInterface */
+ private $factory;
+ private $selectTimeout;
+ private $active;
+ private $handles = [];
+ private $delays = [];
+ private $options = [];
+
+ /**
+ * This handler accepts the following options:
+ *
+ * - handle_factory: An optional factory used to create curl handles
+ * - select_timeout: Optional timeout (in seconds) to block before timing
+ * out while selecting curl handles. Defaults to 1 second.
+ * - options: An associative array of CURLMOPT_* options and
+ * corresponding values for curl_multi_setopt()
+ *
+ * @param array $options
+ */
+ public function __construct(array $options = [])
+ {
+ $this->factory = isset($options['handle_factory'])
+ ? $options['handle_factory'] : new CurlFactory(50);
+
+ if (isset($options['select_timeout'])) {
+ $this->selectTimeout = $options['select_timeout'];
+ } elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
+ $this->selectTimeout = $selectTimeout;
+ } else {
+ $this->selectTimeout = 1;
+ }
+
+ $this->options = isset($options['options']) ? $options['options'] : [];
+ }
+
+ public function __get($name)
+ {
+ if ($name === '_mh') {
+ $this->_mh = curl_multi_init();
+
+ foreach ($this->options as $option => $value) {
+ // A warning is raised in case of a wrong option.
+ curl_multi_setopt($this->_mh, $option, $value);
+ }
+
+ // Further calls to _mh will return the value directly, without entering the
+ // __get() method at all.
+ return $this->_mh;
+ }
+
+ throw new \BadMethodCallException();
+ }
+
+ public function __destruct()
+ {
+ if (isset($this->_mh)) {
+ curl_multi_close($this->_mh);
+ unset($this->_mh);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $easy = $this->factory->create($request, $options);
+ $id = (int) $easy->handle;
+
+ $promise = new Promise(
+ [$this, 'execute'],
+ function () use ($id) {
+ return $this->cancel($id);
+ }
+ );
+
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
+
+ return $promise;
+ }
+
+ /**
+ * Ticks the curl event loop.
+ */
+ public function tick()
+ {
+ // Add any delayed handles if needed.
+ if ($this->delays) {
+ $currentTime = Utils::currentTime();
+ foreach ($this->delays as $id => $delay) {
+ if ($currentTime >= $delay) {
+ unset($this->delays[$id]);
+ curl_multi_add_handle(
+ $this->_mh,
+ $this->handles[$id]['easy']->handle
+ );
+ }
+ }
+ }
+
+ // Step through the task queue which may add additional requests.
+ P\queue()->run();
+
+ if ($this->active &&
+ curl_multi_select($this->_mh, $this->selectTimeout) === -1
+ ) {
+ // Perform a usleep if a select returns -1.
+ // See: https://bugs.php.net/bug.php?id=61141
+ usleep(250);
+ }
+
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
+
+ $this->processMessages();
+ }
+
+ /**
+ * Runs until all outstanding connections have completed.
+ */
+ public function execute()
+ {
+ $queue = P\queue();
+
+ while ($this->handles || !$queue->isEmpty()) {
+ // If there are no transfers, then sleep for the next delay
+ if (!$this->active && $this->delays) {
+ usleep($this->timeToNext());
+ }
+ $this->tick();
+ }
+ }
+
+ private function addRequest(array $entry)
+ {
+ $easy = $entry['easy'];
+ $id = (int) $easy->handle;
+ $this->handles[$id] = $entry;
+ if (empty($easy->options['delay'])) {
+ curl_multi_add_handle($this->_mh, $easy->handle);
+ } else {
+ $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
+ }
+ }
+
+ /**
+ * Cancels a handle from sending and removes references to it.
+ *
+ * @param int $id Handle ID to cancel and remove.
+ *
+ * @return bool True on success, false on failure.
+ */
+ private function cancel($id)
+ {
+ // Cannot cancel if it has been processed.
+ if (!isset($this->handles[$id])) {
+ return false;
+ }
+
+ $handle = $this->handles[$id]['easy']->handle;
+ unset($this->delays[$id], $this->handles[$id]);
+ curl_multi_remove_handle($this->_mh, $handle);
+ curl_close($handle);
+
+ return true;
+ }
+
+ private function processMessages()
+ {
+ while ($done = curl_multi_info_read($this->_mh)) {
+ $id = (int) $done['handle'];
+ curl_multi_remove_handle($this->_mh, $done['handle']);
+
+ if (!isset($this->handles[$id])) {
+ // Probably was cancelled.
+ continue;
+ }
+
+ $entry = $this->handles[$id];
+ unset($this->handles[$id], $this->delays[$id]);
+ $entry['easy']->errno = $done['result'];
+ $entry['deferred']->resolve(
+ CurlFactory::finish(
+ $this,
+ $entry['easy'],
+ $this->factory
+ )
+ );
+ }
+ }
+
+ private function timeToNext()
+ {
+ $currentTime = Utils::currentTime();
+ $nextTime = PHP_INT_MAX;
+ foreach ($this->delays as $time) {
+ if ($time < $nextTime) {
+ $nextTime = $time;
+ }
+ }
+
+ return max(0, $nextTime - $currentTime) * 1000000;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
new file mode 100644
index 0000000..7754e91
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
@@ -0,0 +1,92 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Psr7\Response;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Represents a cURL easy handle and the data it populates.
+ *
+ * @internal
+ */
+final class EasyHandle
+{
+ /** @var resource cURL resource */
+ public $handle;
+
+ /** @var StreamInterface Where data is being written */
+ public $sink;
+
+ /** @var array Received HTTP headers so far */
+ public $headers = [];
+
+ /** @var ResponseInterface Received response (if any) */
+ public $response;
+
+ /** @var RequestInterface Request being sent */
+ public $request;
+
+ /** @var array Request options */
+ public $options = [];
+
+ /** @var int cURL error number (if any) */
+ public $errno = 0;
+
+ /** @var \Exception Exception during on_headers (if any) */
+ public $onHeadersException;
+
+ /**
+ * Attach a response to the easy handle based on the received headers.
+ *
+ * @throws \RuntimeException if no headers have been received.
+ */
+ public function createResponse()
+ {
+ if (empty($this->headers)) {
+ throw new \RuntimeException('No headers have been received');
+ }
+
+ // HTTP-version SP status-code SP reason-phrase
+ $startLine = explode(' ', array_shift($this->headers), 3);
+ $headers = \GuzzleHttp\headers_from_lines($this->headers);
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+
+ if (!empty($this->options['decode_content'])
+ && isset($normalizedKeys['content-encoding'])
+ ) {
+ $headers['x-encoded-content-encoding']
+ = $headers[$normalizedKeys['content-encoding']];
+ unset($headers[$normalizedKeys['content-encoding']]);
+ if (isset($normalizedKeys['content-length'])) {
+ $headers['x-encoded-content-length']
+ = $headers[$normalizedKeys['content-length']];
+
+ $bodyLength = (int) $this->sink->getSize();
+ if ($bodyLength) {
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
+ } else {
+ unset($headers[$normalizedKeys['content-length']]);
+ }
+ }
+ }
+
+ // Attach a response to the easy handle with the parsed headers.
+ $this->response = new Response(
+ $startLine[1],
+ $headers,
+ $this->sink,
+ substr($startLine[0], 5),
+ isset($startLine[2]) ? (string) $startLine[2] : null
+ );
+ }
+
+ public function __get($name)
+ {
+ $msg = $name === 'handle'
+ ? 'The EasyHandle has been released'
+ : 'Invalid property: ' . $name;
+ throw new \BadMethodCallException($msg);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
new file mode 100644
index 0000000..5b312bc
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
@@ -0,0 +1,195 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Promise\RejectedPromise;
+use GuzzleHttp\TransferStats;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Handler that returns responses or throw exceptions from a queue.
+ */
+class MockHandler implements \Countable
+{
+ private $queue = [];
+ private $lastRequest;
+ private $lastOptions;
+ private $onFulfilled;
+ private $onRejected;
+
+ /**
+ * Creates a new MockHandler that uses the default handler stack list of
+ * middlewares.
+ *
+ * @param array $queue Array of responses, callables, or exceptions.
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
+ *
+ * @return HandlerStack
+ */
+ public static function createWithMiddleware(
+ array $queue = null,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
+ }
+
+ /**
+ * The passed in value must be an array of
+ * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
+ * callables, or Promises.
+ *
+ * @param array $queue
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
+ */
+ public function __construct(
+ array $queue = null,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ $this->onFulfilled = $onFulfilled;
+ $this->onRejected = $onRejected;
+
+ if ($queue) {
+ call_user_func_array([$this, 'append'], $queue);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!$this->queue) {
+ throw new \OutOfBoundsException('Mock queue is empty');
+ }
+
+ if (isset($options['delay']) && is_numeric($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $this->lastRequest = $request;
+ $this->lastOptions = $options;
+ $response = array_shift($this->queue);
+
+ if (isset($options['on_headers'])) {
+ if (!is_callable($options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+ try {
+ $options['on_headers']($response);
+ } catch (\Exception $e) {
+ $msg = 'An error was encountered during the on_headers event';
+ $response = new RequestException($msg, $request, $response, $e);
+ }
+ }
+
+ if (is_callable($response)) {
+ $response = call_user_func($response, $request, $options);
+ }
+
+ $response = $response instanceof \Exception
+ ? \GuzzleHttp\Promise\rejection_for($response)
+ : \GuzzleHttp\Promise\promise_for($response);
+
+ return $response->then(
+ function ($value) use ($request, $options) {
+ $this->invokeStats($request, $options, $value);
+ if ($this->onFulfilled) {
+ call_user_func($this->onFulfilled, $value);
+ }
+ if (isset($options['sink'])) {
+ $contents = (string) $value->getBody();
+ $sink = $options['sink'];
+
+ if (is_resource($sink)) {
+ fwrite($sink, $contents);
+ } elseif (is_string($sink)) {
+ file_put_contents($sink, $contents);
+ } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
+ $sink->write($contents);
+ }
+ }
+
+ return $value;
+ },
+ function ($reason) use ($request, $options) {
+ $this->invokeStats($request, $options, null, $reason);
+ if ($this->onRejected) {
+ call_user_func($this->onRejected, $reason);
+ }
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ }
+
+ /**
+ * Adds one or more variadic requests, exceptions, callables, or promises
+ * to the queue.
+ */
+ public function append()
+ {
+ foreach (func_get_args() as $value) {
+ if ($value instanceof ResponseInterface
+ || $value instanceof \Exception
+ || $value instanceof PromiseInterface
+ || is_callable($value)
+ ) {
+ $this->queue[] = $value;
+ } else {
+ throw new \InvalidArgumentException('Expected a response or '
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
+ }
+ }
+ }
+
+ /**
+ * Get the last received request.
+ *
+ * @return RequestInterface
+ */
+ public function getLastRequest()
+ {
+ return $this->lastRequest;
+ }
+
+ /**
+ * Get the last received request options.
+ *
+ * @return array
+ */
+ public function getLastOptions()
+ {
+ return $this->lastOptions;
+ }
+
+ /**
+ * Returns the number of remaining items in the queue.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->queue);
+ }
+
+ public function reset()
+ {
+ $this->queue = [];
+ }
+
+ private function invokeStats(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response = null,
+ $reason = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
+ $stats = new TransferStats($request, $response, $transferTime, $reason);
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php b/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
new file mode 100644
index 0000000..f8b00be
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
@@ -0,0 +1,55 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\RequestOptions;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Provides basic proxies for handlers.
+ */
+class Proxy
+{
+ /**
+ * Sends synchronous requests to a specific handler while sending all other
+ * requests to another handler.
+ *
+ * @param callable $default Handler used for normal responses
+ * @param callable $sync Handler used for synchronous responses.
+ *
+ * @return callable Returns the composed handler.
+ */
+ public static function wrapSync(
+ callable $default,
+ callable $sync
+ ) {
+ return function (RequestInterface $request, array $options) use ($default, $sync) {
+ return empty($options[RequestOptions::SYNCHRONOUS])
+ ? $default($request, $options)
+ : $sync($request, $options);
+ };
+ }
+
+ /**
+ * Sends streaming requests to a streaming compatible handler while sending
+ * all other requests to a default handler.
+ *
+ * This, for example, could be useful for taking advantage of the
+ * performance benefits of curl while still supporting true streaming
+ * through the StreamHandler.
+ *
+ * @param callable $default Handler used for non-streaming responses
+ * @param callable $streaming Handler used for streaming responses
+ *
+ * @return callable Returns the composed handler.
+ */
+ public static function wrapStreaming(
+ callable $default,
+ callable $streaming
+ ) {
+ return function (RequestInterface $request, array $options) use ($default, $streaming) {
+ return empty($options['stream'])
+ ? $default($request, $options)
+ : $streaming($request, $options);
+ };
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
new file mode 100644
index 0000000..a15734a
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
@@ -0,0 +1,545 @@
+<?php
+namespace GuzzleHttp\Handler;
+
+use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise\FulfilledPromise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\TransferStats;
+use GuzzleHttp\Utils;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * HTTP handler that uses PHP's HTTP stream wrapper.
+ */
+class StreamHandler
+{
+ private $lastHeaders = [];
+
+ /**
+ * Sends an HTTP request.
+ *
+ * @param RequestInterface $request Request to send.
+ * @param array $options Request transfer options.
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ // Sleep if there is a delay specified.
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
+
+ try {
+ // Does not support the expect header.
+ $request = $request->withoutHeader('Expect');
+
+ // Append a content-length header if body size is zero to match
+ // cURL's behavior.
+ if (0 === $request->getBody()->getSize()) {
+ $request = $request->withHeader('Content-Length', '0');
+ }
+
+ return $this->createResponse(
+ $request,
+ $options,
+ $this->createStream($request, $options),
+ $startTime
+ );
+ } catch (\InvalidArgumentException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ // Determine if the error was a networking error.
+ $message = $e->getMessage();
+ // This list can probably get more comprehensive.
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
+ || strpos($message, 'Connection refused')
+ || strpos($message, "couldn't connect to host") // error on HHVM
+ || strpos($message, "connection attempt failed")
+ ) {
+ $e = new ConnectException($e->getMessage(), $request, $e);
+ }
+ $e = RequestException::wrapException($request, $e);
+ $this->invokeStats($options, $request, $startTime, null, $e);
+
+ return \GuzzleHttp\Promise\rejection_for($e);
+ }
+ }
+
+ private function invokeStats(
+ array $options,
+ RequestInterface $request,
+ $startTime,
+ ResponseInterface $response = null,
+ $error = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $stats = new TransferStats(
+ $request,
+ $response,
+ Utils::currentTime() - $startTime,
+ $error,
+ []
+ );
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+
+ private function createResponse(
+ RequestInterface $request,
+ array $options,
+ $stream,
+ $startTime
+ ) {
+ $hdrs = $this->lastHeaders;
+ $this->lastHeaders = [];
+ $parts = explode(' ', array_shift($hdrs), 3);
+ $ver = explode('/', $parts[0])[1];
+ $status = $parts[1];
+ $reason = isset($parts[2]) ? $parts[2] : null;
+ $headers = \GuzzleHttp\headers_from_lines($hdrs);
+ list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
+ $stream = Psr7\stream_for($stream);
+ $sink = $stream;
+
+ if (strcasecmp('HEAD', $request->getMethod())) {
+ $sink = $this->createSink($stream, $options);
+ }
+
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
+
+ if (isset($options['on_headers'])) {
+ try {
+ $options['on_headers']($response);
+ } catch (\Exception $e) {
+ $msg = 'An error was encountered during the on_headers event';
+ $ex = new RequestException($msg, $request, $response, $e);
+ return \GuzzleHttp\Promise\rejection_for($ex);
+ }
+ }
+
+ // Do not drain when the request is a HEAD request because they have
+ // no body.
+ if ($sink !== $stream) {
+ $this->drain(
+ $stream,
+ $sink,
+ $response->getHeaderLine('Content-Length')
+ );
+ }
+
+ $this->invokeStats($options, $request, $startTime, $response, null);
+
+ return new FulfilledPromise($response);
+ }
+
+ private function createSink(StreamInterface $stream, array $options)
+ {
+ if (!empty($options['stream'])) {
+ return $stream;
+ }
+
+ $sink = isset($options['sink'])
+ ? $options['sink']
+ : fopen('php://temp', 'r+');
+
+ return is_string($sink)
+ ? new Psr7\LazyOpenStream($sink, 'w+')
+ : Psr7\stream_for($sink);
+ }
+
+ private function checkDecode(array $options, array $headers, $stream)
+ {
+ // Automatically decode responses when instructed.
+ if (!empty($options['decode_content'])) {
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+ if (isset($normalizedKeys['content-encoding'])) {
+ $encoding = $headers[$normalizedKeys['content-encoding']];
+ if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
+ $stream = new Psr7\InflateStream(
+ Psr7\stream_for($stream)
+ );
+ $headers['x-encoded-content-encoding']
+ = $headers[$normalizedKeys['content-encoding']];
+ // Remove content-encoding header
+ unset($headers[$normalizedKeys['content-encoding']]);
+ // Fix content-length header
+ if (isset($normalizedKeys['content-length'])) {
+ $headers['x-encoded-content-length']
+ = $headers[$normalizedKeys['content-length']];
+
+ $length = (int) $stream->getSize();
+ if ($length === 0) {
+ unset($headers[$normalizedKeys['content-length']]);
+ } else {
+ $headers[$normalizedKeys['content-length']] = [$length];
+ }
+ }
+ }
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ /**
+ * Drains the source stream into the "sink" client option.
+ *
+ * @param StreamInterface $source
+ * @param StreamInterface $sink
+ * @param string $contentLength Header specifying the amount of
+ * data to read.
+ *
+ * @return StreamInterface
+ * @throws \RuntimeException when the sink option is invalid.
+ */
+ private function drain(
+ StreamInterface $source,
+ StreamInterface $sink,
+ $contentLength
+ ) {
+ // If a content-length header is provided, then stop reading once
+ // that number of bytes has been read. This can prevent infinitely
+ // reading from a stream when dealing with servers that do not honor
+ // Connection: Close headers.
+ Psr7\copy_to_stream(
+ $source,
+ $sink,
+ (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
+ );
+
+ $sink->seek(0);
+ $source->close();
+
+ return $sink;
+ }
+
+ /**
+ * Create a resource and check to ensure it was created successfully
+ *
+ * @param callable $callback Callable that returns stream resource
+ *
+ * @return resource
+ * @throws \RuntimeException on error
+ */
+ private function createResource(callable $callback)
+ {
+ $errors = null;
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
+ $errors[] = [
+ 'message' => $msg,
+ 'file' => $file,
+ 'line' => $line
+ ];
+ return true;
+ });
+
+ $resource = $callback();
+ restore_error_handler();
+
+ if (!$resource) {
+ $message = 'Error creating resource: ';
+ foreach ($errors as $err) {
+ foreach ($err as $key => $value) {
+ $message .= "[$key] $value" . PHP_EOL;
+ }
+ }
+ throw new \RuntimeException(trim($message));
+ }
+
+ return $resource;
+ }
+
+ private function createStream(RequestInterface $request, array $options)
+ {
+ static $methods;
+ if (!$methods) {
+ $methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ // HTTP/1.1 streams using the PHP stream wrapper require a
+ // Connection: close header
+ if ($request->getProtocolVersion() == '1.1'
+ && !$request->hasHeader('Connection')
+ ) {
+ $request = $request->withHeader('Connection', 'close');
+ }
+
+ // Ensure SSL is verified by default
+ if (!isset($options['verify'])) {
+ $options['verify'] = true;
+ }
+
+ $params = [];
+ $context = $this->getDefaultContext($request);
+
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+
+ if (!empty($options)) {
+ foreach ($options as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $context, $value, $params);
+ }
+ }
+ }
+
+ if (isset($options['stream_context'])) {
+ if (!is_array($options['stream_context'])) {
+ throw new \InvalidArgumentException('stream_context must be an array');
+ }
+ $context = array_replace_recursive(
+ $context,
+ $options['stream_context']
+ );
+ }
+
+ // Microsoft NTLM authentication only supported with curl handler
+ if (isset($options['auth'])
+ && is_array($options['auth'])
+ && isset($options['auth'][2])
+ && 'ntlm' == $options['auth'][2]
+ ) {
+ throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
+ }
+
+ $uri = $this->resolveHost($request, $options);
+
+ $context = $this->createResource(
+ function () use ($context, $params) {
+ return stream_context_create($context, $params);
+ }
+ );
+
+ return $this->createResource(
+ function () use ($uri, &$http_response_header, $context, $options) {
+ $resource = fopen((string) $uri, 'r', null, $context);
+ $this->lastHeaders = $http_response_header;
+
+ if (isset($options['read_timeout'])) {
+ $readTimeout = $options['read_timeout'];
+ $sec = (int) $readTimeout;
+ $usec = ($readTimeout - $sec) * 100000;
+ stream_set_timeout($resource, $sec, $usec);
+ }
+
+ return $resource;
+ }
+ );
+ }
+
+ private function resolveHost(RequestInterface $request, array $options)
+ {
+ $uri = $request->getUri();
+
+ if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
+ if ('v4' === $options['force_ip_resolve']) {
+ $records = dns_get_record($uri->getHost(), DNS_A);
+ if (!isset($records[0]['ip'])) {
+ throw new ConnectException(
+ sprintf(
+ "Could not resolve IPv4 address for host '%s'",
+ $uri->getHost()
+ ),
+ $request
+ );
+ }
+ $uri = $uri->withHost($records[0]['ip']);
+ } elseif ('v6' === $options['force_ip_resolve']) {
+ $records = dns_get_record($uri->getHost(), DNS_AAAA);
+ if (!isset($records[0]['ipv6'])) {
+ throw new ConnectException(
+ sprintf(
+ "Could not resolve IPv6 address for host '%s'",
+ $uri->getHost()
+ ),
+ $request
+ );
+ }
+ $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
+ }
+ }
+
+ return $uri;
+ }
+
+ private function getDefaultContext(RequestInterface $request)
+ {
+ $headers = '';
+ foreach ($request->getHeaders() as $name => $value) {
+ foreach ($value as $val) {
+ $headers .= "$name: $val\r\n";
+ }
+ }
+
+ $context = [
+ 'http' => [
+ 'method' => $request->getMethod(),
+ 'header' => $headers,
+ 'protocol_version' => $request->getProtocolVersion(),
+ 'ignore_errors' => true,
+ 'follow_location' => 0,
+ ],
+ ];
+
+ $body = (string) $request->getBody();
+
+ if (!empty($body)) {
+ $context['http']['content'] = $body;
+ // Prevent the HTTP handler from adding a Content-Type header.
+ if (!$request->hasHeader('Content-Type')) {
+ $context['http']['header'] .= "Content-Type:\r\n";
+ }
+ }
+
+ $context['http']['header'] = rtrim($context['http']['header']);
+
+ return $context;
+ }
+
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (!is_array($value)) {
+ $options['http']['proxy'] = $value;
+ } else {
+ $scheme = $request->getUri()->getScheme();
+ if (isset($value[$scheme])) {
+ if (!isset($value['no'])
+ || !\GuzzleHttp\is_host_in_noproxy(
+ $request->getUri()->getHost(),
+ $value['no']
+ )
+ ) {
+ $options['http']['proxy'] = $value[$scheme];
+ }
+ }
+ }
+ }
+
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value > 0) {
+ $options['http']['timeout'] = $value;
+ }
+ }
+
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value === true) {
+ // PHP 5.6 or greater will find the system cert by default. When
+ // < 5.6, use the Guzzle bundled cacert.
+ if (PHP_VERSION_ID < 50600) {
+ $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
+ }
+ } elseif (is_string($value)) {
+ $options['ssl']['cafile'] = $value;
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL CA bundle not found: $value");
+ }
+ } elseif ($value === false) {
+ $options['ssl']['verify_peer'] = false;
+ $options['ssl']['verify_peer_name'] = false;
+ return;
+ } else {
+ throw new \InvalidArgumentException('Invalid verify request option');
+ }
+
+ $options['ssl']['verify_peer'] = true;
+ $options['ssl']['verify_peer_name'] = true;
+ $options['ssl']['allow_self_signed'] = false;
+ }
+
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (is_array($value)) {
+ $options['ssl']['passphrase'] = $value[1];
+ $value = $value[0];
+ }
+
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL certificate not found: {$value}");
+ }
+
+ $options['ssl']['local_cert'] = $value;
+ }
+
+ private function add_progress(RequestInterface $request, &$options, $value, &$params)
+ {
+ $this->addNotification(
+ $params,
+ function ($code, $a, $b, $c, $transferred, $total) use ($value) {
+ if ($code == STREAM_NOTIFY_PROGRESS) {
+ $value($total, $transferred, null, null);
+ }
+ }
+ );
+ }
+
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value === false) {
+ return;
+ }
+
+ static $map = [
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
+ ];
+ static $args = ['severity', 'message', 'message_code',
+ 'bytes_transferred', 'bytes_max'];
+
+ $value = \GuzzleHttp\debug_resource($value);
+ $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
+ $this->addNotification(
+ $params,
+ function () use ($ident, $value, $map, $args) {
+ $passed = func_get_args();
+ $code = array_shift($passed);
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
+ foreach (array_filter($passed) as $i => $v) {
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
+ }
+ fwrite($value, "\n");
+ }
+ );
+ }
+
+ private function addNotification(array &$params, callable $notify)
+ {
+ // Wrap the existing function if needed.
+ if (!isset($params['notification'])) {
+ $params['notification'] = $notify;
+ } else {
+ $params['notification'] = $this->callArray([
+ $params['notification'],
+ $notify
+ ]);
+ }
+ }
+
+ private function callArray(array $functions)
+ {
+ return function () use ($functions) {
+ $args = func_get_args();
+ foreach ($functions as $fn) {
+ call_user_func_array($fn, $args);
+ }
+ };
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/HandlerStack.php b/vendor/guzzlehttp/guzzle/src/HandlerStack.php
new file mode 100644
index 0000000..6a49cc0
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/HandlerStack.php
@@ -0,0 +1,277 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Creates a composed Guzzle handler function by stacking middlewares on top of
+ * an HTTP handler function.
+ */
+class HandlerStack
+{
+ /** @var callable|null */
+ private $handler;
+
+ /** @var array */
+ private $stack = [];
+
+ /** @var callable|null */
+ private $cached;
+
+ /**
+ * Creates a default handler stack that can be used by clients.
+ *
+ * The returned handler will wrap the provided handler or use the most
+ * appropriate default handler for your system. The returned HandlerStack has
+ * support for cookies, redirects, HTTP error exceptions, and preparing a body
+ * before sending.
+ *
+ * The returned handler stack can be passed to a client in the "handler"
+ * option.
+ *
+ * @param callable $handler HTTP handler function to use with the stack. If no
+ * handler is provided, the best handler for your
+ * system will be utilized.
+ *
+ * @return HandlerStack
+ */
+ public static function create(callable $handler = null)
+ {
+ $stack = new self($handler ?: choose_handler());
+ $stack->push(Middleware::httpErrors(), 'http_errors');
+ $stack->push(Middleware::redirect(), 'allow_redirects');
+ $stack->push(Middleware::cookies(), 'cookies');
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
+
+ return $stack;
+ }
+
+ /**
+ * @param callable $handler Underlying HTTP handler.
+ */
+ public function __construct(callable $handler = null)
+ {
+ $this->handler = $handler;
+ }
+
+ /**
+ * Invokes the handler stack as a composed handler
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $handler = $this->resolve();
+
+ return $handler($request, $options);
+ }
+
+ /**
+ * Dumps a string representation of the stack.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $depth = 0;
+ $stack = [];
+ if ($this->handler) {
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
+ }
+
+ $result = '';
+ foreach (array_reverse($this->stack) as $tuple) {
+ $depth++;
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
+ $result = "> {$str}\n{$result}";
+ $stack[] = $str;
+ }
+
+ foreach (array_keys($stack) as $k) {
+ $result .= "< {$stack[$k]}\n";
+ }
+
+ return $result;
+ }
+
+ /**
+ * Set the HTTP handler that actually returns a promise.
+ *
+ * @param callable $handler Accepts a request and array of options and
+ * returns a Promise.
+ */
+ public function setHandler(callable $handler)
+ {
+ $this->handler = $handler;
+ $this->cached = null;
+ }
+
+ /**
+ * Returns true if the builder has a handler.
+ *
+ * @return bool
+ */
+ public function hasHandler()
+ {
+ return (bool) $this->handler;
+ }
+
+ /**
+ * Unshift a middleware to the bottom of the stack.
+ *
+ * @param callable $middleware Middleware function
+ * @param string $name Name to register for this middleware.
+ */
+ public function unshift(callable $middleware, $name = null)
+ {
+ array_unshift($this->stack, [$middleware, $name]);
+ $this->cached = null;
+ }
+
+ /**
+ * Push a middleware to the top of the stack.
+ *
+ * @param callable $middleware Middleware function
+ * @param string $name Name to register for this middleware.
+ */
+ public function push(callable $middleware, $name = '')
+ {
+ $this->stack[] = [$middleware, $name];
+ $this->cached = null;
+ }
+
+ /**
+ * Add a middleware before another middleware by name.
+ *
+ * @param string $findName Middleware to find
+ * @param callable $middleware Middleware function
+ * @param string $withName Name to register for this middleware.
+ */
+ public function before($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, true);
+ }
+
+ /**
+ * Add a middleware after another middleware by name.
+ *
+ * @param string $findName Middleware to find
+ * @param callable $middleware Middleware function
+ * @param string $withName Name to register for this middleware.
+ */
+ public function after($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, false);
+ }
+
+ /**
+ * Remove a middleware by instance or name from the stack.
+ *
+ * @param callable|string $remove Middleware to remove by instance or name.
+ */
+ public function remove($remove)
+ {
+ $this->cached = null;
+ $idx = is_callable($remove) ? 0 : 1;
+ $this->stack = array_values(array_filter(
+ $this->stack,
+ function ($tuple) use ($idx, $remove) {
+ return $tuple[$idx] !== $remove;
+ }
+ ));
+ }
+
+ /**
+ * Compose the middleware and handler into a single callable function.
+ *
+ * @return callable
+ */
+ public function resolve()
+ {
+ if (!$this->cached) {
+ if (!($prev = $this->handler)) {
+ throw new \LogicException('No handler has been specified');
+ }
+
+ foreach (array_reverse($this->stack) as $fn) {
+ $prev = $fn[0]($prev);
+ }
+
+ $this->cached = $prev;
+ }
+
+ return $this->cached;
+ }
+
+ /**
+ * @param string $name
+ * @return int
+ */
+ private function findByName($name)
+ {
+ foreach ($this->stack as $k => $v) {
+ if ($v[1] === $name) {
+ return $k;
+ }
+ }
+
+ throw new \InvalidArgumentException("Middleware not found: $name");
+ }
+
+ /**
+ * Splices a function into the middleware list at a specific position.
+ *
+ * @param string $findName
+ * @param string $withName
+ * @param callable $middleware
+ * @param bool $before
+ */
+ private function splice($findName, $withName, callable $middleware, $before)
+ {
+ $this->cached = null;
+ $idx = $this->findByName($findName);
+ $tuple = [$middleware, $withName];
+
+ if ($before) {
+ if ($idx === 0) {
+ array_unshift($this->stack, $tuple);
+ } else {
+ $replacement = [$tuple, $this->stack[$idx]];
+ array_splice($this->stack, $idx, 1, $replacement);
+ }
+ } elseif ($idx === count($this->stack) - 1) {
+ $this->stack[] = $tuple;
+ } else {
+ $replacement = [$this->stack[$idx], $tuple];
+ array_splice($this->stack, $idx, 1, $replacement);
+ }
+ }
+
+ /**
+ * Provides a debug string for a given callable.
+ *
+ * @param array|callable $fn Function to write as a string.
+ *
+ * @return string
+ */
+ private function debugCallable($fn)
+ {
+ if (is_string($fn)) {
+ return "callable({$fn})";
+ }
+
+ if (is_array($fn)) {
+ return is_string($fn[0])
+ ? "callable({$fn[0]}::{$fn[1]})"
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
+ }
+
+ return 'callable(' . spl_object_hash($fn) . ')';
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/MessageFormatter.php b/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
new file mode 100644
index 0000000..dc36bb5
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
@@ -0,0 +1,185 @@
+<?php
+namespace GuzzleHttp;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Formats log messages using variable substitutions for requests, responses,
+ * and other transactional data.
+ *
+ * The following variable substitutions are supported:
+ *
+ * - {request}: Full HTTP request message
+ * - {response}: Full HTTP response message
+ * - {ts}: ISO 8601 date in GMT
+ * - {date_iso_8601} ISO 8601 date in GMT
+ * - {date_common_log} Apache common log date using the configured timezone.
+ * - {host}: Host of the request
+ * - {method}: Method of the request
+ * - {uri}: URI of the request
+ * - {version}: Protocol version
+ * - {target}: Request target of the request (path + query + fragment)
+ * - {hostname}: Hostname of the machine that sent the request
+ * - {code}: Status code of the response (if available)
+ * - {phrase}: Reason phrase of the response (if available)
+ * - {error}: Any error messages (if available)
+ * - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
+ * - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
+ * - {req_headers}: Request headers
+ * - {res_headers}: Response headers
+ * - {req_body}: Request body
+ * - {res_body}: Response body
+ */
+class MessageFormatter
+{
+ /**
+ * Apache Common Log Format.
+ * @link http://httpd.apache.org/docs/2.4/logs.html#common
+ * @var string
+ */
+ const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
+ const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
+
+ /** @var string Template used to format log messages */
+ private $template;
+
+ /**
+ * @param string $template Log message template
+ */
+ public function __construct($template = self::CLF)
+ {
+ $this->template = $template ?: self::CLF;
+ }
+
+ /**
+ * Returns a formatted message string.
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param ResponseInterface $response Response that was received
+ * @param \Exception $error Exception that was received
+ *
+ * @return string
+ */
+ public function format(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $error = null
+ ) {
+ $cache = [];
+
+ return preg_replace_callback(
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
+ function (array $matches) use ($request, $response, $error, &$cache) {
+ if (isset($cache[$matches[1]])) {
+ return $cache[$matches[1]];
+ }
+
+ $result = '';
+ switch ($matches[1]) {
+ case 'request':
+ $result = Psr7\str($request);
+ break;
+ case 'response':
+ $result = $response ? Psr7\str($response) : '';
+ break;
+ case 'req_headers':
+ $result = trim($request->getMethod()
+ . ' ' . $request->getRequestTarget())
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
+ . $this->headers($request);
+ break;
+ case 'res_headers':
+ $result = $response ?
+ sprintf(
+ 'HTTP/%s %d %s',
+ $response->getProtocolVersion(),
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ ) . "\r\n" . $this->headers($response)
+ : 'NULL';
+ break;
+ case 'req_body':
+ $result = $request->getBody();
+ break;
+ case 'res_body':
+ $result = $response ? $response->getBody() : 'NULL';
+ break;
+ case 'ts':
+ case 'date_iso_8601':
+ $result = gmdate('c');
+ break;
+ case 'date_common_log':
+ $result = date('d/M/Y:H:i:s O');
+ break;
+ case 'method':
+ $result = $request->getMethod();
+ break;
+ case 'version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'uri':
+ case 'url':
+ $result = $request->getUri();
+ break;
+ case 'target':
+ $result = $request->getRequestTarget();
+ break;
+ case 'req_version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'res_version':
+ $result = $response
+ ? $response->getProtocolVersion()
+ : 'NULL';
+ break;
+ case 'host':
+ $result = $request->getHeaderLine('Host');
+ break;
+ case 'hostname':
+ $result = gethostname();
+ break;
+ case 'code':
+ $result = $response ? $response->getStatusCode() : 'NULL';
+ break;
+ case 'phrase':
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
+ break;
+ case 'error':
+ $result = $error ? $error->getMessage() : 'NULL';
+ break;
+ default:
+ // handle prefixed dynamic headers
+ if (strpos($matches[1], 'req_header_') === 0) {
+ $result = $request->getHeaderLine(substr($matches[1], 11));
+ } elseif (strpos($matches[1], 'res_header_') === 0) {
+ $result = $response
+ ? $response->getHeaderLine(substr($matches[1], 11))
+ : 'NULL';
+ }
+ }
+
+ $cache[$matches[1]] = $result;
+ return $result;
+ },
+ $this->template
+ );
+ }
+
+ /**
+ * Get headers from message as string
+ *
+ * @return string
+ */
+ private function headers(MessageInterface $message)
+ {
+ $result = '';
+ foreach ($message->getHeaders() as $name => $values) {
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
+ }
+
+ return trim($result);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Middleware.php b/vendor/guzzlehttp/guzzle/src/Middleware.php
new file mode 100644
index 0000000..bffc197
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Middleware.php
@@ -0,0 +1,254 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Cookie\CookieJarInterface;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Promise\RejectedPromise;
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Functions used to create and wrap handlers with handler middleware.
+ */
+final class Middleware
+{
+ /**
+ * Middleware that adds cookies to requests.
+ *
+ * The options array must be set to a CookieJarInterface in order to use
+ * cookies. This is typically handled for you by a client.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function cookies()
+ {
+ return function (callable $handler) {
+ return function ($request, array $options) use ($handler) {
+ if (empty($options['cookies'])) {
+ return $handler($request, $options);
+ } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
+ throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
+ }
+ $cookieJar = $options['cookies'];
+ $request = $cookieJar->withCookieHeader($request);
+ return $handler($request, $options)
+ ->then(
+ function ($response) use ($cookieJar, $request) {
+ $cookieJar->extractCookies($request, $response);
+ return $response;
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that throws exceptions for 4xx or 5xx responses when the
+ * "http_error" request option is set to true.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function httpErrors()
+ {
+ return function (callable $handler) {
+ return function ($request, array $options) use ($handler) {
+ if (empty($options['http_errors'])) {
+ return $handler($request, $options);
+ }
+ return $handler($request, $options)->then(
+ function (ResponseInterface $response) use ($request) {
+ $code = $response->getStatusCode();
+ if ($code < 400) {
+ return $response;
+ }
+ throw RequestException::create($request, $response);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that pushes history data to an ArrayAccess container.
+ *
+ * @param array|\ArrayAccess $container Container to hold the history (by reference).
+ *
+ * @return callable Returns a function that accepts the next handler.
+ * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
+ */
+ public static function history(&$container)
+ {
+ if (!is_array($container) && !$container instanceof \ArrayAccess) {
+ throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
+ }
+
+ return function (callable $handler) use (&$container) {
+ return function ($request, array $options) use ($handler, &$container) {
+ return $handler($request, $options)->then(
+ function ($value) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => $value,
+ 'error' => null,
+ 'options' => $options
+ ];
+ return $value;
+ },
+ function ($reason) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => null,
+ 'error' => $reason,
+ 'options' => $options
+ ];
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that invokes a callback before and after sending a request.
+ *
+ * The provided listener cannot modify or alter the response. It simply
+ * "taps" into the chain to be notified before returning the promise. The
+ * before listener accepts a request and options array, and the after
+ * listener accepts a request, options array, and response promise.
+ *
+ * @param callable $before Function to invoke before forwarding the request.
+ * @param callable $after Function invoked after forwarding.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function tap(callable $before = null, callable $after = null)
+ {
+ return function (callable $handler) use ($before, $after) {
+ return function ($request, array $options) use ($handler, $before, $after) {
+ if ($before) {
+ $before($request, $options);
+ }
+ $response = $handler($request, $options);
+ if ($after) {
+ $after($request, $options, $response);
+ }
+ return $response;
+ };
+ };
+ }
+
+ /**
+ * Middleware that handles request redirects.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function redirect()
+ {
+ return function (callable $handler) {
+ return new RedirectMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that retries requests based on the boolean result of
+ * invoking the provided "decider" function.
+ *
+ * If no delay function is provided, a simple implementation of exponential
+ * backoff will be utilized.
+ *
+ * @param callable $decider Function that accepts the number of retries,
+ * a request, [response], and [exception] and
+ * returns true if the request is to be retried.
+ * @param callable $delay Function that accepts the number of retries and
+ * returns the number of milliseconds to delay.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function retry(callable $decider, callable $delay = null)
+ {
+ return function (callable $handler) use ($decider, $delay) {
+ return new RetryMiddleware($decider, $handler, $delay);
+ };
+ }
+
+ /**
+ * Middleware that logs requests, responses, and errors using a message
+ * formatter.
+ *
+ * @param LoggerInterface $logger Logs messages.
+ * @param MessageFormatter $formatter Formatter used to create message strings.
+ * @param string $logLevel Level at which to log requests.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */)
+ {
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
+ return $handler($request, $options)->then(
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
+ $message = $formatter->format($request, $response);
+ $logger->log($logLevel, $message);
+ return $response;
+ },
+ function ($reason) use ($logger, $request, $formatter) {
+ $response = $reason instanceof RequestException
+ ? $reason->getResponse()
+ : null;
+ $message = $formatter->format($request, $response, $reason);
+ $logger->notice($message);
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * This middleware adds a default content-type if possible, a default
+ * content-length or transfer-encoding header, and the expect header.
+ *
+ * @return callable
+ */
+ public static function prepareBody()
+ {
+ return function (callable $handler) {
+ return new PrepareBodyMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the request before passing to
+ * the next handler.
+ *
+ * @param callable $fn Function that accepts a RequestInterface and returns
+ * a RequestInterface.
+ * @return callable
+ */
+ public static function mapRequest(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($fn($request), $options);
+ };
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the resolved promise's
+ * response.
+ *
+ * @param callable $fn Function that accepts a ResponseInterface and
+ * returns a ResponseInterface.
+ * @return callable
+ */
+ public static function mapResponse(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($request, $options)->then($fn);
+ };
+ };
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Pool.php b/vendor/guzzlehttp/guzzle/src/Pool.php
new file mode 100644
index 0000000..5838db4
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Pool.php
@@ -0,0 +1,134 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Promise\EachPromise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Promise\PromisorInterface;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Sends an iterator of requests concurrently using a capped pool size.
+ *
+ * The pool will read from an iterator until it is cancelled or until the
+ * iterator is consumed. When a request is yielded, the request is sent after
+ * applying the "request_options" request options (if provided in the ctor).
+ *
+ * When a function is yielded by the iterator, the function is provided the
+ * "request_options" array that should be merged on top of any existing
+ * options, and the function MUST then return a wait-able promise.
+ */
+class Pool implements PromisorInterface
+{
+ /** @var EachPromise */
+ private $each;
+
+ /**
+ * @param ClientInterface $client Client used to send the requests.
+ * @param array|\Iterator $requests Requests or functions that return
+ * requests to send concurrently.
+ * @param array $config Associative array of options
+ * - concurrency: (int) Maximum number of requests to send concurrently
+ * - options: Array of request options to apply to each request.
+ * - fulfilled: (callable) Function to invoke when a request completes.
+ * - rejected: (callable) Function to invoke when a request is rejected.
+ */
+ public function __construct(
+ ClientInterface $client,
+ $requests,
+ array $config = []
+ ) {
+ // Backwards compatibility.
+ if (isset($config['pool_size'])) {
+ $config['concurrency'] = $config['pool_size'];
+ } elseif (!isset($config['concurrency'])) {
+ $config['concurrency'] = 25;
+ }
+
+ if (isset($config['options'])) {
+ $opts = $config['options'];
+ unset($config['options']);
+ } else {
+ $opts = [];
+ }
+
+ $iterable = \GuzzleHttp\Promise\iter_for($requests);
+ $requests = function () use ($iterable, $client, $opts) {
+ foreach ($iterable as $key => $rfn) {
+ if ($rfn instanceof RequestInterface) {
+ yield $key => $client->sendAsync($rfn, $opts);
+ } elseif (is_callable($rfn)) {
+ yield $key => $rfn($opts);
+ } else {
+ throw new \InvalidArgumentException('Each value yielded by '
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
+ . 'or a callable that returns a promise that fulfills '
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
+ }
+ }
+ };
+
+ $this->each = new EachPromise($requests(), $config);
+ }
+
+ /**
+ * Get promise
+ *
+ * @return PromiseInterface
+ */
+ public function promise()
+ {
+ return $this->each->promise();
+ }
+
+ /**
+ * Sends multiple requests concurrently and returns an array of responses
+ * and exceptions that uses the same ordering as the provided requests.
+ *
+ * IMPORTANT: This method keeps every request and response in memory, and
+ * as such, is NOT recommended when sending a large number or an
+ * indeterminate number of requests concurrently.
+ *
+ * @param ClientInterface $client Client used to send the requests
+ * @param array|\Iterator $requests Requests to send concurrently.
+ * @param array $options Passes through the options available in
+ * {@see GuzzleHttp\Pool::__construct}
+ *
+ * @return array Returns an array containing the response or an exception
+ * in the same order that the requests were sent.
+ * @throws \InvalidArgumentException if the event format is incorrect.
+ */
+ public static function batch(
+ ClientInterface $client,
+ $requests,
+ array $options = []
+ ) {
+ $res = [];
+ self::cmpCallback($options, 'fulfilled', $res);
+ self::cmpCallback($options, 'rejected', $res);
+ $pool = new static($client, $requests, $options);
+ $pool->promise()->wait();
+ ksort($res);
+
+ return $res;
+ }
+
+ /**
+ * Execute callback(s)
+ *
+ * @return void
+ */
+ private static function cmpCallback(array &$options, $name, array &$results)
+ {
+ if (!isset($options[$name])) {
+ $options[$name] = function ($v, $k) use (&$results) {
+ $results[$k] = $v;
+ };
+ } else {
+ $currentFn = $options[$name];
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
+ $currentFn($v, $k);
+ $results[$k] = $v;
+ };
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
new file mode 100644
index 0000000..568a1e9
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
@@ -0,0 +1,111 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Prepares requests that contain a body, adding the Content-Length,
+ * Content-Type, and Expect headers.
+ */
+class PrepareBodyMiddleware
+{
+ /** @var callable */
+ private $nextHandler;
+
+ /**
+ * @param callable $nextHandler Next handler to invoke.
+ */
+ public function __construct(callable $nextHandler)
+ {
+ $this->nextHandler = $nextHandler;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $fn = $this->nextHandler;
+
+ // Don't do anything if the request has no body.
+ if ($request->getBody()->getSize() === 0) {
+ return $fn($request, $options);
+ }
+
+ $modify = [];
+
+ // Add a default content-type if possible.
+ if (!$request->hasHeader('Content-Type')) {
+ if ($uri = $request->getBody()->getMetadata('uri')) {
+ if ($type = Psr7\mimetype_from_filename($uri)) {
+ $modify['set_headers']['Content-Type'] = $type;
+ }
+ }
+ }
+
+ // Add a default content-length or transfer-encoding header.
+ if (!$request->hasHeader('Content-Length')
+ && !$request->hasHeader('Transfer-Encoding')
+ ) {
+ $size = $request->getBody()->getSize();
+ if ($size !== null) {
+ $modify['set_headers']['Content-Length'] = $size;
+ } else {
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
+ }
+ }
+
+ // Add the expect header if needed.
+ $this->addExpectHeader($request, $options, $modify);
+
+ return $fn(Psr7\modify_request($request, $modify), $options);
+ }
+
+ /**
+ * Add expect header
+ *
+ * @return void
+ */
+ private function addExpectHeader(
+ RequestInterface $request,
+ array $options,
+ array &$modify
+ ) {
+ // Determine if the Expect header should be used
+ if ($request->hasHeader('Expect')) {
+ return;
+ }
+
+ $expect = isset($options['expect']) ? $options['expect'] : null;
+
+ // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
+ if ($expect === false || $request->getProtocolVersion() < 1.1) {
+ return;
+ }
+
+ // The expect header is unconditionally enabled
+ if ($expect === true) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ return;
+ }
+
+ // By default, send the expect header when the payload is > 1mb
+ if ($expect === null) {
+ $expect = 1048576;
+ }
+
+ // Always add if the body cannot be rewound, the size cannot be
+ // determined, or the size is greater than the cutoff threshold
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php b/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
new file mode 100644
index 0000000..fd86c60
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
@@ -0,0 +1,281 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Exception\BadResponseException;
+use GuzzleHttp\Exception\TooManyRedirectsException;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Request redirect middleware.
+ *
+ * Apply this middleware like other middleware using
+ * {@see \GuzzleHttp\Middleware::redirect()}.
+ */
+class RedirectMiddleware
+{
+ const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
+
+ const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
+
+ public static $defaultSettings = [
+ 'max' => 5,
+ 'protocols' => ['http', 'https'],
+ 'strict' => false,
+ 'referer' => false,
+ 'track_redirects' => false,
+ ];
+
+ /** @var callable */
+ private $nextHandler;
+
+ /**
+ * @param callable $nextHandler Next handler to invoke.
+ */
+ public function __construct(callable $nextHandler)
+ {
+ $this->nextHandler = $nextHandler;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $fn = $this->nextHandler;
+
+ if (empty($options['allow_redirects'])) {
+ return $fn($request, $options);
+ }
+
+ if ($options['allow_redirects'] === true) {
+ $options['allow_redirects'] = self::$defaultSettings;
+ } elseif (!is_array($options['allow_redirects'])) {
+ throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
+ } else {
+ // Merge the default settings with the provided settings
+ $options['allow_redirects'] += self::$defaultSettings;
+ }
+
+ if (empty($options['allow_redirects']['max'])) {
+ return $fn($request, $options);
+ }
+
+ return $fn($request, $options)
+ ->then(function (ResponseInterface $response) use ($request, $options) {
+ return $this->checkRedirect($request, $options, $response);
+ });
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface $response
+ *
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function checkRedirect(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ if (substr($response->getStatusCode(), 0, 1) != '3'
+ || !$response->hasHeader('Location')
+ ) {
+ return $response;
+ }
+
+ $this->guardMax($request, $options);
+ $nextRequest = $this->modifyRequest($request, $options, $response);
+
+ if (isset($options['allow_redirects']['on_redirect'])) {
+ call_user_func(
+ $options['allow_redirects']['on_redirect'],
+ $request,
+ $response,
+ $nextRequest->getUri()
+ );
+ }
+
+ /** @var PromiseInterface|ResponseInterface $promise */
+ $promise = $this($nextRequest, $options);
+
+ // Add headers to be able to track history of redirects.
+ if (!empty($options['allow_redirects']['track_redirects'])) {
+ return $this->withTracking(
+ $promise,
+ (string) $nextRequest->getUri(),
+ $response->getStatusCode()
+ );
+ }
+
+ return $promise;
+ }
+
+ /**
+ * Enable tracking on promise.
+ *
+ * @return PromiseInterface
+ */
+ private function withTracking(PromiseInterface $promise, $uri, $statusCode)
+ {
+ return $promise->then(
+ function (ResponseInterface $response) use ($uri, $statusCode) {
+ // Note that we are pushing to the front of the list as this
+ // would be an earlier response than what is currently present
+ // in the history header.
+ $historyHeader = $response->getHeader(self::HISTORY_HEADER);
+ $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
+ array_unshift($historyHeader, $uri);
+ array_unshift($statusHeader, $statusCode);
+ return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
+ ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
+ }
+ );
+ }
+
+ /**
+ * Check for too many redirects.
+ *
+ * @return void
+ *
+ * @throws TooManyRedirectsException Too many redirects.
+ */
+ private function guardMax(RequestInterface $request, array &$options)
+ {
+ $current = isset($options['__redirect_count'])
+ ? $options['__redirect_count']
+ : 0;
+ $options['__redirect_count'] = $current + 1;
+ $max = $options['allow_redirects']['max'];
+
+ if ($options['__redirect_count'] > $max) {
+ throw new TooManyRedirectsException(
+ "Will not follow more than {$max} redirects",
+ $request
+ );
+ }
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface $response
+ *
+ * @return RequestInterface
+ */
+ public function modifyRequest(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ // Request modifications to apply.
+ $modify = [];
+ $protocols = $options['allow_redirects']['protocols'];
+
+ // Use a GET request if this is an entity enclosing request and we are
+ // not forcing RFC compliance, but rather emulating what all browsers
+ // would do.
+ $statusCode = $response->getStatusCode();
+ if ($statusCode == 303 ||
+ ($statusCode <= 302 && !$options['allow_redirects']['strict'])
+ ) {
+ $modify['method'] = 'GET';
+ $modify['body'] = '';
+ }
+
+ $uri = self::redirectUri($request, $response, $protocols);
+ if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
+ $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
+ $uri = Utils::idnUriConvert($uri, $idnOptions);
+ }
+
+ $modify['uri'] = $uri;
+ Psr7\rewind_body($request);
+
+ // Add the Referer header if it is told to do so and only
+ // add the header if we are not redirecting from https to http.
+ if ($options['allow_redirects']['referer']
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
+ ) {
+ $uri = $request->getUri()->withUserInfo('');
+ $modify['set_headers']['Referer'] = (string) $uri;
+ } else {
+ $modify['remove_headers'][] = 'Referer';
+ }
+
+ // Remove Authorization and Cookie headers if required.
+ if (self::shouldStripSensitiveHeaders($request->getUri(), $modify['uri'])) {
+ $modify['remove_headers'][] = 'Authorization';
+ $modify['remove_headers'][] = 'Cookie';
+ }
+
+ return Psr7\modify_request($request, $modify);
+ }
+
+ /**
+ * Determine if we should strip sensitive headers from the request.
+ *
+ * We return true if either of the following conditions are true:
+ *
+ * 1. the host is different;
+ * 2. the scheme has changed, and now is non-https.
+ *
+ * @return bool
+ */
+ private static function shouldStripSensitiveHeaders(
+ UriInterface $originalUri,
+ UriInterface $modifiedUri
+ ) {
+ if (strcasecmp($originalUri->getHost(), $modifiedUri->getHost()) !== 0) {
+ return true;
+ }
+
+ if ($originalUri->getScheme() !== $modifiedUri->getScheme() && 'https' !== $modifiedUri->getScheme()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Set the appropriate URL on the request based on the location header.
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @param array $protocols
+ *
+ * @return UriInterface
+ */
+ private static function redirectUri(
+ RequestInterface $request,
+ ResponseInterface $response,
+ array $protocols
+ ) {
+ $location = Psr7\UriResolver::resolve(
+ $request->getUri(),
+ new Psr7\Uri($response->getHeaderLine('Location'))
+ );
+
+ // Ensure that the redirect URI is allowed based on the protocols.
+ if (!in_array($location->getScheme(), $protocols)) {
+ throw new BadResponseException(
+ sprintf(
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
+ $location,
+ implode(', ', $protocols)
+ ),
+ $request,
+ $response
+ );
+ }
+
+ return $location;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/RequestOptions.php b/vendor/guzzlehttp/guzzle/src/RequestOptions.php
new file mode 100644
index 0000000..355f658
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/RequestOptions.php
@@ -0,0 +1,263 @@
+<?php
+namespace GuzzleHttp;
+
+/**
+ * This class contains a list of built-in Guzzle request options.
+ *
+ * More documentation for each option can be found at http://guzzlephp.org/.
+ *
+ * @link http://docs.guzzlephp.org/en/v6/request-options.html
+ */
+final class RequestOptions
+{
+ /**
+ * allow_redirects: (bool|array) Controls redirect behavior. Pass false
+ * to disable redirects, pass true to enable redirects, pass an
+ * associative to provide custom redirect settings. Defaults to "false".
+ * This option only works if your handler has the RedirectMiddleware. When
+ * passing an associative array, you can provide the following key value
+ * pairs:
+ *
+ * - max: (int, default=5) maximum number of allowed redirects.
+ * - strict: (bool, default=false) Set to true to use strict redirects
+ * meaning redirect POST requests with POST requests vs. doing what most
+ * browsers do which is redirect POST requests with GET requests
+ * - referer: (bool, default=false) Set to true to enable the Referer
+ * header.
+ * - protocols: (array, default=['http', 'https']) Allowed redirect
+ * protocols.
+ * - on_redirect: (callable) PHP callable that is invoked when a redirect
+ * is encountered. The callable is invoked with the request, the redirect
+ * response that was received, and the effective URI. Any return value
+ * from the on_redirect function is ignored.
+ */
+ const ALLOW_REDIRECTS = 'allow_redirects';
+
+ /**
+ * auth: (array) Pass an array of HTTP authentication parameters to use
+ * with the request. The array must contain the username in index [0],
+ * the password in index [1], and you can optionally provide a built-in
+ * authentication type in index [2]. Pass null to disable authentication
+ * for a request.
+ */
+ const AUTH = 'auth';
+
+ /**
+ * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
+ * Body to send in the request.
+ */
+ const BODY = 'body';
+
+ /**
+ * cert: (string|array) Set to a string to specify the path to a file
+ * containing a PEM formatted SSL client side certificate. If a password
+ * is required, then set cert to an array containing the path to the PEM
+ * file in the first array element followed by the certificate password
+ * in the second array element.
+ */
+ const CERT = 'cert';
+
+ /**
+ * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
+ * Specifies whether or not cookies are used in a request or what cookie
+ * jar to use or what cookies to send. This option only works if your
+ * handler has the `cookie` middleware. Valid values are `false` and
+ * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
+ */
+ const COOKIES = 'cookies';
+
+ /**
+ * connect_timeout: (float, default=0) Float describing the number of
+ * seconds to wait while trying to connect to a server. Use 0 to wait
+ * indefinitely (the default behavior).
+ */
+ const CONNECT_TIMEOUT = 'connect_timeout';
+
+ /**
+ * debug: (bool|resource) Set to true or set to a PHP stream returned by
+ * fopen() enable debug output with the HTTP handler used to send a
+ * request.
+ */
+ const DEBUG = 'debug';
+
+ /**
+ * decode_content: (bool, default=true) Specify whether or not
+ * Content-Encoding responses (gzip, deflate, etc.) are automatically
+ * decoded.
+ */
+ const DECODE_CONTENT = 'decode_content';
+
+ /**
+ * delay: (int) The amount of time to delay before sending in milliseconds.
+ */
+ const DELAY = 'delay';
+
+ /**
+ * expect: (bool|integer) Controls the behavior of the
+ * "Expect: 100-Continue" header.
+ *
+ * Set to `true` to enable the "Expect: 100-Continue" header for all
+ * requests that sends a body. Set to `false` to disable the
+ * "Expect: 100-Continue" header for all requests. Set to a number so that
+ * the size of the payload must be greater than the number in order to send
+ * the Expect header. Setting to a number will send the Expect header for
+ * all requests in which the size of the payload cannot be determined or
+ * where the body is not rewindable.
+ *
+ * By default, Guzzle will add the "Expect: 100-Continue" header when the
+ * size of the body of a request is greater than 1 MB and a request is
+ * using HTTP/1.1.
+ */
+ const EXPECT = 'expect';
+
+ /**
+ * form_params: (array) Associative array of form field names to values
+ * where each value is a string or array of strings. Sets the Content-Type
+ * header to application/x-www-form-urlencoded when no Content-Type header
+ * is already present.
+ */
+ const FORM_PARAMS = 'form_params';
+
+ /**
+ * headers: (array) Associative array of HTTP headers. Each value MUST be
+ * a string or array of strings.
+ */
+ const HEADERS = 'headers';
+
+ /**
+ * http_errors: (bool, default=true) Set to false to disable exceptions
+ * when a non- successful HTTP response is received. By default,
+ * exceptions will be thrown for 4xx and 5xx responses. This option only
+ * works if your handler has the `httpErrors` middleware.
+ */
+ const HTTP_ERRORS = 'http_errors';
+
+ /**
+ * idn: (bool|int, default=true) A combination of IDNA_* constants for
+ * idn_to_ascii() PHP's function (see "options" parameter). Set to false to
+ * disable IDN support completely, or to true to use the default
+ * configuration (IDNA_DEFAULT constant).
+ */
+ const IDN_CONVERSION = 'idn_conversion';
+
+ /**
+ * json: (mixed) Adds JSON data to a request. The provided value is JSON
+ * encoded and a Content-Type header of application/json will be added to
+ * the request if no Content-Type header is already present.
+ */
+ const JSON = 'json';
+
+ /**
+ * multipart: (array) Array of associative arrays, each containing a
+ * required "name" key mapping to the form field, name, a required
+ * "contents" key mapping to a StreamInterface|resource|string, an
+ * optional "headers" associative array of custom headers, and an
+ * optional "filename" key mapping to a string to send as the filename in
+ * the part. If no "filename" key is present, then no "filename" attribute
+ * will be added to the part.
+ */
+ const MULTIPART = 'multipart';
+
+ /**
+ * on_headers: (callable) A callable that is invoked when the HTTP headers
+ * of the response have been received but the body has not yet begun to
+ * download.
+ */
+ const ON_HEADERS = 'on_headers';
+
+ /**
+ * on_stats: (callable) allows you to get access to transfer statistics of
+ * a request and access the lower level transfer details of the handler
+ * associated with your client. ``on_stats`` is a callable that is invoked
+ * when a handler has finished sending a request. The callback is invoked
+ * with transfer statistics about the request, the response received, or
+ * the error encountered. Included in the data is the total amount of time
+ * taken to send the request.
+ */
+ const ON_STATS = 'on_stats';
+
+ /**
+ * progress: (callable) Defines a function to invoke when transfer
+ * progress is made. The function accepts the following positional
+ * arguments: the total number of bytes expected to be downloaded, the
+ * number of bytes downloaded so far, the number of bytes expected to be
+ * uploaded, the number of bytes uploaded so far.
+ */
+ const PROGRESS = 'progress';
+
+ /**
+ * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
+ * array to specify different proxies for different protocols (where the
+ * key is the protocol and the value is a proxy string).
+ */
+ const PROXY = 'proxy';
+
+ /**
+ * query: (array|string) Associative array of query string values to add
+ * to the request. This option uses PHP's http_build_query() to create
+ * the string representation. Pass a string value if you need more
+ * control than what this method provides
+ */
+ const QUERY = 'query';
+
+ /**
+ * sink: (resource|string|StreamInterface) Where the data of the
+ * response is written to. Defaults to a PHP temp stream. Providing a
+ * string will write data to a file by the given name.
+ */
+ const SINK = 'sink';
+
+ /**
+ * synchronous: (bool) Set to true to inform HTTP handlers that you intend
+ * on waiting on the response. This can be useful for optimizations. Note
+ * that a promise is still returned if you are using one of the async
+ * client methods.
+ */
+ const SYNCHRONOUS = 'synchronous';
+
+ /**
+ * ssl_key: (array|string) Specify the path to a file containing a private
+ * SSL key in PEM format. If a password is required, then set to an array
+ * containing the path to the SSL key in the first array element followed
+ * by the password required for the certificate in the second element.
+ */
+ const SSL_KEY = 'ssl_key';
+
+ /**
+ * stream: Set to true to attempt to stream a response rather than
+ * download it all up-front.
+ */
+ const STREAM = 'stream';
+
+ /**
+ * verify: (bool|string, default=true) Describes the SSL certificate
+ * verification behavior of a request. Set to true to enable SSL
+ * certificate verification using the system CA bundle when available
+ * (the default). Set to false to disable certificate verification (this
+ * is insecure!). Set to a string to provide the path to a CA bundle on
+ * disk to enable verification using a custom certificate.
+ */
+ const VERIFY = 'verify';
+
+ /**
+ * timeout: (float, default=0) Float describing the timeout of the
+ * request in seconds. Use 0 to wait indefinitely (the default behavior).
+ */
+ const TIMEOUT = 'timeout';
+
+ /**
+ * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
+ * the body read timeout, for stream requests.
+ */
+ const READ_TIMEOUT = 'read_timeout';
+
+ /**
+ * version: (float) Specifies the HTTP protocol version to attempt to use.
+ */
+ const VERSION = 'version';
+
+ /**
+ * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
+ */
+ const FORCE_IP_RESOLVE = 'force_ip_resolve';
+}
diff --git a/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php b/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
new file mode 100644
index 0000000..5acc8c5
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
@@ -0,0 +1,128 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Promise\RejectedPromise;
+use GuzzleHttp\Psr7;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Middleware that retries requests based on the boolean result of
+ * invoking the provided "decider" function.
+ */
+class RetryMiddleware
+{
+ /** @var callable */
+ private $nextHandler;
+
+ /** @var callable */
+ private $decider;
+
+ /** @var callable */
+ private $delay;
+
+ /**
+ * @param callable $decider Function that accepts the number of retries,
+ * a request, [response], and [exception] and
+ * returns true if the request is to be
+ * retried.
+ * @param callable $nextHandler Next handler to invoke.
+ * @param callable $delay Function that accepts the number of retries
+ * and [response] and returns the number of
+ * milliseconds to delay.
+ */
+ public function __construct(
+ callable $decider,
+ callable $nextHandler,
+ callable $delay = null
+ ) {
+ $this->decider = $decider;
+ $this->nextHandler = $nextHandler;
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
+ }
+
+ /**
+ * Default exponential backoff delay function.
+ *
+ * @param int $retries
+ *
+ * @return int milliseconds.
+ */
+ public static function exponentialDelay($retries)
+ {
+ return (int) pow(2, $retries - 1) * 1000;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!isset($options['retries'])) {
+ $options['retries'] = 0;
+ }
+
+ $fn = $this->nextHandler;
+ return $fn($request, $options)
+ ->then(
+ $this->onFulfilled($request, $options),
+ $this->onRejected($request, $options)
+ );
+ }
+
+ /**
+ * Execute fulfilled closure
+ *
+ * @return mixed
+ */
+ private function onFulfilled(RequestInterface $req, array $options)
+ {
+ return function ($value) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ $value,
+ null
+ )) {
+ return $value;
+ }
+ return $this->doRetry($req, $options, $value);
+ };
+ }
+
+ /**
+ * Execute rejected closure
+ *
+ * @return callable
+ */
+ private function onRejected(RequestInterface $req, array $options)
+ {
+ return function ($reason) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ null,
+ $reason
+ )) {
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ return $this->doRetry($req, $options);
+ };
+ }
+
+ /**
+ * @return self
+ */
+ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
+ {
+ $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
+
+ return $this($request, $options);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/TransferStats.php b/vendor/guzzlehttp/guzzle/src/TransferStats.php
new file mode 100644
index 0000000..87fb3c0
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/TransferStats.php
@@ -0,0 +1,126 @@
+<?php
+namespace GuzzleHttp;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Represents data at the point after it was transferred either successfully
+ * or after a network error.
+ */
+final class TransferStats
+{
+ private $request;
+ private $response;
+ private $transferTime;
+ private $handlerStats;
+ private $handlerErrorData;
+
+ /**
+ * @param RequestInterface $request Request that was sent.
+ * @param ResponseInterface|null $response Response received (if any)
+ * @param float|null $transferTime Total handler transfer time.
+ * @param mixed $handlerErrorData Handler error data.
+ * @param array $handlerStats Handler specific stats.
+ */
+ public function __construct(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ $transferTime = null,
+ $handlerErrorData = null,
+ $handlerStats = []
+ ) {
+ $this->request = $request;
+ $this->response = $response;
+ $this->transferTime = $transferTime;
+ $this->handlerErrorData = $handlerErrorData;
+ $this->handlerStats = $handlerStats;
+ }
+
+ /**
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Returns the response that was received (if any).
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Returns true if a response was received.
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Gets handler specific error data.
+ *
+ * This might be an exception, a integer representing an error code, or
+ * anything else. Relying on this value assumes that you know what handler
+ * you are using.
+ *
+ * @return mixed
+ */
+ public function getHandlerErrorData()
+ {
+ return $this->handlerErrorData;
+ }
+
+ /**
+ * Get the effective URI the request was sent to.
+ *
+ * @return UriInterface
+ */
+ public function getEffectiveUri()
+ {
+ return $this->request->getUri();
+ }
+
+ /**
+ * Get the estimated time the request was being transferred by the handler.
+ *
+ * @return float|null Time in seconds.
+ */
+ public function getTransferTime()
+ {
+ return $this->transferTime;
+ }
+
+ /**
+ * Gets an array of all of the handler specific transfer data.
+ *
+ * @return array
+ */
+ public function getHandlerStats()
+ {
+ return $this->handlerStats;
+ }
+
+ /**
+ * Get a specific handler statistic from the handler by name.
+ *
+ * @param string $stat Handler specific transfer stat to retrieve.
+ *
+ * @return mixed|null
+ */
+ public function getHandlerStat($stat)
+ {
+ return isset($this->handlerStats[$stat])
+ ? $this->handlerStats[$stat]
+ : null;
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/UriTemplate.php b/vendor/guzzlehttp/guzzle/src/UriTemplate.php
new file mode 100644
index 0000000..96dcfd0
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/UriTemplate.php
@@ -0,0 +1,237 @@
+<?php
+namespace GuzzleHttp;
+
+/**
+ * Expands URI templates. Userland implementation of PECL uri_template.
+ *
+ * @link http://tools.ietf.org/html/rfc6570
+ */
+class UriTemplate
+{
+ /** @var string URI template */
+ private $template;
+
+ /** @var array Variables to use in the template expansion */
+ private $variables;
+
+ /** @var array Hash for quick operator lookups */
+ private static $operatorHash = [
+ '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
+ '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
+ '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
+ '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
+ '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
+ ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
+ '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
+ '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
+ ];
+
+ /** @var array Delimiters */
+ private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
+ '&', '\'', '(', ')', '*', '+', ',', ';', '='];
+
+ /** @var array Percent encoded delimiters */
+ private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
+ '%3B', '%3D'];
+
+ public function expand($template, array $variables)
+ {
+ if (false === strpos($template, '{')) {
+ return $template;
+ }
+
+ $this->template = $template;
+ $this->variables = $variables;
+
+ return preg_replace_callback(
+ '/\{([^\}]+)\}/',
+ [$this, 'expandMatch'],
+ $this->template
+ );
+ }
+
+ /**
+ * Parse an expression into parts
+ *
+ * @param string $expression Expression to parse
+ *
+ * @return array Returns an associative array of parts
+ */
+ private function parseExpression($expression)
+ {
+ $result = [];
+
+ if (isset(self::$operatorHash[$expression[0]])) {
+ $result['operator'] = $expression[0];
+ $expression = substr($expression, 1);
+ } else {
+ $result['operator'] = '';
+ }
+
+ foreach (explode(',', $expression) as $value) {
+ $value = trim($value);
+ $varspec = [];
+ if ($colonPos = strpos($value, ':')) {
+ $varspec['value'] = substr($value, 0, $colonPos);
+ $varspec['modifier'] = ':';
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
+ } elseif (substr($value, -1) === '*') {
+ $varspec['modifier'] = '*';
+ $varspec['value'] = substr($value, 0, -1);
+ } else {
+ $varspec['value'] = (string) $value;
+ $varspec['modifier'] = '';
+ }
+ $result['values'][] = $varspec;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Process an expansion
+ *
+ * @param array $matches Matches met in the preg_replace_callback
+ *
+ * @return string Returns the replacement string
+ */
+ private function expandMatch(array $matches)
+ {
+ static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
+
+ $replacements = [];
+ $parsed = self::parseExpression($matches[1]);
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
+
+ foreach ($parsed['values'] as $value) {
+ if (!isset($this->variables[$value['value']])) {
+ continue;
+ }
+
+ $variable = $this->variables[$value['value']];
+ $actuallyUseQuery = $useQuery;
+ $expanded = '';
+
+ if (is_array($variable)) {
+ $isAssoc = $this->isAssoc($variable);
+ $kvp = [];
+ foreach ($variable as $key => $var) {
+ if ($isAssoc) {
+ $key = rawurlencode($key);
+ $isNestedArray = is_array($var);
+ } else {
+ $isNestedArray = false;
+ }
+
+ if (!$isNestedArray) {
+ $var = rawurlencode($var);
+ if ($parsed['operator'] === '+' ||
+ $parsed['operator'] === '#'
+ ) {
+ $var = $this->decodeReserved($var);
+ }
+ }
+
+ if ($value['modifier'] === '*') {
+ if ($isAssoc) {
+ if ($isNestedArray) {
+ // Nested arrays must allow for deeply nested
+ // structures.
+ $var = strtr(
+ http_build_query([$key => $var]),
+ $rfc1738to3986
+ );
+ } else {
+ $var = $key . '=' . $var;
+ }
+ } elseif ($key > 0 && $actuallyUseQuery) {
+ $var = $value['value'] . '=' . $var;
+ }
+ }
+
+ $kvp[$key] = $var;
+ }
+
+ if (empty($variable)) {
+ $actuallyUseQuery = false;
+ } elseif ($value['modifier'] === '*') {
+ $expanded = implode($joiner, $kvp);
+ if ($isAssoc) {
+ // Don't prepend the value name when using the explode
+ // modifier with an associative array.
+ $actuallyUseQuery = false;
+ }
+ } else {
+ if ($isAssoc) {
+ // When an associative array is encountered and the
+ // explode modifier is not set, then the result must be
+ // a comma separated list of keys followed by their
+ // respective values.
+ foreach ($kvp as $k => &$v) {
+ $v = $k . ',' . $v;
+ }
+ }
+ $expanded = implode(',', $kvp);
+ }
+ } else {
+ if ($value['modifier'] === ':') {
+ $variable = substr($variable, 0, $value['position']);
+ }
+ $expanded = rawurlencode($variable);
+ if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
+ $expanded = $this->decodeReserved($expanded);
+ }
+ }
+
+ if ($actuallyUseQuery) {
+ if (!$expanded && $joiner !== '&') {
+ $expanded = $value['value'];
+ } else {
+ $expanded = $value['value'] . '=' . $expanded;
+ }
+ }
+
+ $replacements[] = $expanded;
+ }
+
+ $ret = implode($joiner, $replacements);
+ if ($ret && $prefix) {
+ return $prefix . $ret;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Determines if an array is associative.
+ *
+ * This makes the assumption that input arrays are sequences or hashes.
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
+ * should work in almost every case where input is supplied for a URI
+ * template.
+ *
+ * @param array $array Array to check
+ *
+ * @return bool
+ */
+ private function isAssoc(array $array)
+ {
+ return $array && array_keys($array)[0] !== 0;
+ }
+
+ /**
+ * Removes percent encoding on reserved characters (used with + and #
+ * modifiers).
+ *
+ * @param string $string String to fix
+ *
+ * @return string
+ */
+ private function decodeReserved($string)
+ {
+ return str_replace(self::$delimsPct, self::$delims, $string);
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/Utils.php b/vendor/guzzlehttp/guzzle/src/Utils.php
new file mode 100644
index 0000000..c698acb
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/Utils.php
@@ -0,0 +1,92 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Exception\InvalidArgumentException;
+use Psr\Http\Message\UriInterface;
+use Symfony\Polyfill\Intl\Idn\Idn;
+
+final class Utils
+{
+ /**
+ * Wrapper for the hrtime() or microtime() functions
+ * (depending on the PHP version, one of the two is used)
+ *
+ * @return float|mixed UNIX timestamp
+ *
+ * @internal
+ */
+ public static function currentTime()
+ {
+ return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
+ }
+
+ /**
+ * @param int $options
+ *
+ * @return UriInterface
+ * @throws InvalidArgumentException
+ *
+ * @internal
+ */
+ public static function idnUriConvert(UriInterface $uri, $options = 0)
+ {
+ if ($uri->getHost()) {
+ $asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
+ if ($asciiHost === false) {
+ $errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
+
+ $errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
+ return substr($name, 0, 11) === 'IDNA_ERROR_';
+ });
+
+ $errors = [];
+ foreach ($errorConstants as $errorConstant) {
+ if ($errorBitSet & constant($errorConstant)) {
+ $errors[] = $errorConstant;
+ }
+ }
+
+ $errorMessage = 'IDN conversion failed';
+ if ($errors) {
+ $errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
+ }
+
+ throw new InvalidArgumentException($errorMessage);
+ } else {
+ if ($uri->getHost() !== $asciiHost) {
+ // Replace URI only if the ASCII version is different
+ $uri = $uri->withHost($asciiHost);
+ }
+ }
+ }
+
+ return $uri;
+ }
+
+ /**
+ * @param string $domain
+ * @param int $options
+ * @param array $info
+ *
+ * @return string|false
+ */
+ private static function idnToAsci($domain, $options, &$info = [])
+ {
+ if (\preg_match('%^[ -~]+$%', $domain) === 1) {
+ return $domain;
+ }
+
+ if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
+ return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
+ }
+
+ /*
+ * The Idn class is marked as @internal. Verify that class and method exists.
+ */
+ if (method_exists(Idn::class, 'idn_to_ascii')) {
+ return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
+ }
+
+ throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');
+ }
+}
diff --git a/vendor/guzzlehttp/guzzle/src/functions.php b/vendor/guzzlehttp/guzzle/src/functions.php
new file mode 100644
index 0000000..c2afd8c
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/functions.php
@@ -0,0 +1,334 @@
+<?php
+namespace GuzzleHttp;
+
+use GuzzleHttp\Handler\CurlHandler;
+use GuzzleHttp\Handler\CurlMultiHandler;
+use GuzzleHttp\Handler\Proxy;
+use GuzzleHttp\Handler\StreamHandler;
+
+/**
+ * Expands a URI template
+ *
+ * @param string $template URI template
+ * @param array $variables Template variables
+ *
+ * @return string
+ */
+function uri_template($template, array $variables)
+{
+ if (extension_loaded('uri_template')) {
+ // @codeCoverageIgnoreStart
+ return \uri_template($template, $variables);
+ // @codeCoverageIgnoreEnd
+ }
+
+ static $uriTemplate;
+ if (!$uriTemplate) {
+ $uriTemplate = new UriTemplate();
+ }
+
+ return $uriTemplate->expand($template, $variables);
+}
+
+/**
+ * Debug function used to describe the provided value type and class.
+ *
+ * @param mixed $input
+ *
+ * @return string Returns a string containing the type of the variable and
+ * if a class is provided, the class name.
+ */
+function describe_type($input)
+{
+ switch (gettype($input)) {
+ case 'object':
+ return 'object(' . get_class($input) . ')';
+ case 'array':
+ return 'array(' . count($input) . ')';
+ default:
+ ob_start();
+ var_dump($input);
+ // normalize float vs double
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
+ }
+}
+
+/**
+ * Parses an array of header lines into an associative array of headers.
+ *
+ * @param iterable $lines Header lines array of strings in the following
+ * format: "Name: Value"
+ * @return array
+ */
+function headers_from_lines($lines)
+{
+ $headers = [];
+
+ foreach ($lines as $line) {
+ $parts = explode(':', $line, 2);
+ $headers[trim($parts[0])][] = isset($parts[1])
+ ? trim($parts[1])
+ : null;
+ }
+
+ return $headers;
+}
+
+/**
+ * Returns a debug stream based on the provided variable.
+ *
+ * @param mixed $value Optional value
+ *
+ * @return resource
+ */
+function debug_resource($value = null)
+{
+ if (is_resource($value)) {
+ return $value;
+ } elseif (defined('STDOUT')) {
+ return STDOUT;
+ }
+
+ return fopen('php://output', 'w');
+}
+
+/**
+ * Chooses and creates a default handler to use based on the environment.
+ *
+ * The returned handler is not wrapped by any default middlewares.
+ *
+ * @return callable Returns the best handler for the given system.
+ * @throws \RuntimeException if no viable Handler is available.
+ */
+function choose_handler()
+{
+ $handler = null;
+ if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
+ } elseif (function_exists('curl_exec')) {
+ $handler = new CurlHandler();
+ } elseif (function_exists('curl_multi_exec')) {
+ $handler = new CurlMultiHandler();
+ }
+
+ if (ini_get('allow_url_fopen')) {
+ $handler = $handler
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
+ : new StreamHandler();
+ } elseif (!$handler) {
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
+ }
+
+ return $handler;
+}
+
+/**
+ * Get the default User-Agent string to use with Guzzle
+ *
+ * @return string
+ */
+function default_user_agent()
+{
+ static $defaultAgent = '';
+
+ if (!$defaultAgent) {
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
+ if (extension_loaded('curl') && function_exists('curl_version')) {
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
+ }
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
+ }
+
+ return $defaultAgent;
+}
+
+/**
+ * Returns the default cacert bundle for the current system.
+ *
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
+ * If those settings are not configured, then the common locations for
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
+ * and Windows are checked. If any of these file locations are found on
+ * disk, they will be utilized.
+ *
+ * Note: the result of this function is cached for subsequent calls.
+ *
+ * @return string
+ * @throws \RuntimeException if no bundle can be found.
+ */
+function default_ca_bundle()
+{
+ static $cached = null;
+ static $cafiles = [
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
+ '/etc/pki/tls/certs/ca-bundle.crt',
+ // Ubuntu, Debian (provided by the ca-certificates package)
+ '/etc/ssl/certs/ca-certificates.crt',
+ // FreeBSD (provided by the ca_root_nss package)
+ '/usr/local/share/certs/ca-root-nss.crt',
+ // SLES 12 (provided by the ca-certificates package)
+ '/var/lib/ca-certificates/ca-bundle.pem',
+ // OS X provided by homebrew (using the default path)
+ '/usr/local/etc/openssl/cert.pem',
+ // Google app engine
+ '/etc/ca-certificates.crt',
+ // Windows?
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
+ 'C:\\windows\\curl-ca-bundle.crt',
+ ];
+
+ if ($cached) {
+ return $cached;
+ }
+
+ if ($ca = ini_get('openssl.cafile')) {
+ return $cached = $ca;
+ }
+
+ if ($ca = ini_get('curl.cainfo')) {
+ return $cached = $ca;
+ }
+
+ foreach ($cafiles as $filename) {
+ if (file_exists($filename)) {
+ return $cached = $filename;
+ }
+ }
+
+ throw new \RuntimeException(
+ <<< EOT
+No system CA bundle could be found in any of the the common system locations.
+PHP versions earlier than 5.6 are not properly configured to use the system's
+CA bundle by default. In order to verify peer certificates, you will need to
+supply the path on disk to a certificate bundle to the 'verify' request
+option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
+need a specific certificate bundle, then Mozilla provides a commonly used CA
+bundle which can be downloaded here (provided by the maintainer of cURL):
+https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
+you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
+ini setting to point to the path to the file, allowing you to omit the 'verify'
+request option. See http://curl.haxx.se/docs/sslcerts.html for more
+information.
+EOT
+ );
+}
+
+/**
+ * Creates an associative array of lowercase header names to the actual
+ * header casing.
+ *
+ * @param array $headers
+ *
+ * @return array
+ */
+function normalize_header_keys(array $headers)
+{
+ $result = [];
+ foreach (array_keys($headers) as $key) {
+ $result[strtolower($key)] = $key;
+ }
+
+ return $result;
+}
+
+/**
+ * Returns true if the provided host matches any of the no proxy areas.
+ *
+ * This method will strip a port from the host if it is present. Each pattern
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
+ * "baz.foo.com", but ".foo.com" != "foo.com").
+ *
+ * Areas are matched in the following cases:
+ * 1. "*" (without quotes) always matches any hosts.
+ * 2. An exact match.
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
+ *
+ * @param string $host Host to check against the patterns.
+ * @param array $noProxyArray An array of host patterns.
+ *
+ * @return bool
+ */
+function is_host_in_noproxy($host, array $noProxyArray)
+{
+ if (strlen($host) === 0) {
+ throw new \InvalidArgumentException('Empty host provided');
+ }
+
+ // Strip port if present.
+ if (strpos($host, ':')) {
+ $host = explode($host, ':', 2)[0];
+ }
+
+ foreach ($noProxyArray as $area) {
+ // Always match on wildcards.
+ if ($area === '*') {
+ return true;
+ } elseif (empty($area)) {
+ // Don't match on empty values.
+ continue;
+ } elseif ($area === $host) {
+ // Exact matches.
+ return true;
+ } else {
+ // Special match if the area when prefixed with ".". Remove any
+ // existing leading "." and add a new leading ".".
+ $area = '.' . ltrim($area, '.');
+ if (substr($host, -(strlen($area))) === $area) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Wrapper for json_decode that throws when an error occurs.
+ *
+ * @param string $json JSON data to parse
+ * @param bool $assoc When true, returned objects will be converted
+ * into associative arrays.
+ * @param int $depth User specified recursion depth.
+ * @param int $options Bitmask of JSON decode options.
+ *
+ * @return mixed
+ * @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
+ * @link http://www.php.net/manual/en/function.json-decode.php
+ */
+function json_decode($json, $assoc = false, $depth = 512, $options = 0)
+{
+ $data = \json_decode($json, $assoc, $depth, $options);
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new Exception\InvalidArgumentException(
+ 'json_decode error: ' . json_last_error_msg()
+ );
+ }
+
+ return $data;
+}
+
+/**
+ * Wrapper for JSON encoding that throws when an error occurs.
+ *
+ * @param mixed $value The value being encoded
+ * @param int $options JSON encode option bitmask
+ * @param int $depth Set the maximum depth. Must be greater than zero.
+ *
+ * @return string
+ * @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
+ * @link http://www.php.net/manual/en/function.json-encode.php
+ */
+function json_encode($value, $options = 0, $depth = 512)
+{
+ $json = \json_encode($value, $options, $depth);
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new Exception\InvalidArgumentException(
+ 'json_encode error: ' . json_last_error_msg()
+ );
+ }
+
+ return $json;
+}
diff --git a/vendor/guzzlehttp/guzzle/src/functions_include.php b/vendor/guzzlehttp/guzzle/src/functions_include.php
new file mode 100644
index 0000000..a93393a
--- /dev/null
+++ b/vendor/guzzlehttp/guzzle/src/functions_include.php
@@ -0,0 +1,6 @@
+<?php
+
+// Don't redefine the functions if included multiple times.
+if (!function_exists('GuzzleHttp\uri_template')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/guzzlehttp/promises/LICENSE b/vendor/guzzlehttp/promises/LICENSE
new file mode 100644
index 0000000..9f0f943
--- /dev/null
+++ b/vendor/guzzlehttp/promises/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Michael Dowling <mtdowling@gmail.com>
+Copyright (c) 2015 Graham Campbell <hello@gjcampbell.co.uk>
+Copyright (c) 2017 Tobias Schultze <webmaster@tubo-world.de>
+Copyright (c) 2020 Tobias Nyholm <tobias.nyholm@gmail.com>
+
+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/guzzlehttp/promises/composer.json b/vendor/guzzlehttp/promises/composer.json
new file mode 100644
index 0000000..c959fb3
--- /dev/null
+++ b/vendor/guzzlehttp/promises/composer.json
@@ -0,0 +1,58 @@
+{
+ "name": "guzzlehttp/promises",
+ "description": "Guzzle promises library",
+ "keywords": ["promise"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "test": "vendor/bin/simple-phpunit",
+ "test-ci": "vendor/bin/simple-phpunit --coverage-text"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.5-dev"
+ }
+ },
+ "config": {
+ "preferred-install": "dist",
+ "sort-packages": true
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/AggregateException.php b/vendor/guzzlehttp/promises/src/AggregateException.php
new file mode 100644
index 0000000..d2b5712
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/AggregateException.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Exception thrown when too many errors occur in the some() or any() methods.
+ */
+class AggregateException extends RejectionException
+{
+ public function __construct($msg, array $reasons)
+ {
+ parent::__construct(
+ $reasons,
+ sprintf('%s; %d rejected promises', $msg, count($reasons))
+ );
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/CancellationException.php b/vendor/guzzlehttp/promises/src/CancellationException.php
new file mode 100644
index 0000000..56a1ed6
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/CancellationException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Exception that is set as the reason for a promise that has been cancelled.
+ */
+class CancellationException extends RejectionException
+{
+}
diff --git a/vendor/guzzlehttp/promises/src/Coroutine.php b/vendor/guzzlehttp/promises/src/Coroutine.php
new file mode 100644
index 0000000..670da47
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Coroutine.php
@@ -0,0 +1,169 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+use Exception;
+use Generator;
+use Throwable;
+
+/**
+ * Creates a promise that is resolved using a generator that yields values or
+ * promises (somewhat similar to C#'s async keyword).
+ *
+ * When called, the Coroutine::of method will start an instance of the generator
+ * and returns a promise that is fulfilled with its final yielded value.
+ *
+ * Control is returned back to the generator when the yielded promise settles.
+ * This can lead to less verbose code when doing lots of sequential async calls
+ * with minimal processing in between.
+ *
+ * use GuzzleHttp\Promise;
+ *
+ * function createPromise($value) {
+ * return new Promise\FulfilledPromise($value);
+ * }
+ *
+ * $promise = Promise\Coroutine::of(function () {
+ * $value = (yield createPromise('a'));
+ * try {
+ * $value = (yield createPromise($value . 'b'));
+ * } catch (\Exception $e) {
+ * // The promise was rejected.
+ * }
+ * yield $value . 'c';
+ * });
+ *
+ * // Outputs "abc"
+ * $promise->then(function ($v) { echo $v; });
+ *
+ * @param callable $generatorFn Generator function to wrap into a promise.
+ *
+ * @return Promise
+ *
+ * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
+ */
+final class Coroutine implements PromiseInterface
+{
+ /**
+ * @var PromiseInterface|null
+ */
+ private $currentPromise;
+
+ /**
+ * @var Generator
+ */
+ private $generator;
+
+ /**
+ * @var Promise
+ */
+ private $result;
+
+ public function __construct(callable $generatorFn)
+ {
+ $this->generator = $generatorFn();
+ $this->result = new Promise(function () {
+ while (isset($this->currentPromise)) {
+ $this->currentPromise->wait();
+ }
+ });
+ try {
+ $this->nextCoroutine($this->generator->current());
+ } catch (\Exception $exception) {
+ $this->result->reject($exception);
+ } catch (Throwable $throwable) {
+ $this->result->reject($throwable);
+ }
+ }
+
+ /**
+ * Create a new coroutine.
+ *
+ * @return self
+ */
+ public static function of(callable $generatorFn)
+ {
+ return new self($generatorFn);
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ return $this->result->then($onFulfilled, $onRejected);
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->result->otherwise($onRejected);
+ }
+
+ public function wait($unwrap = true)
+ {
+ return $this->result->wait($unwrap);
+ }
+
+ public function getState()
+ {
+ return $this->result->getState();
+ }
+
+ public function resolve($value)
+ {
+ $this->result->resolve($value);
+ }
+
+ public function reject($reason)
+ {
+ $this->result->reject($reason);
+ }
+
+ public function cancel()
+ {
+ $this->currentPromise->cancel();
+ $this->result->cancel();
+ }
+
+ private function nextCoroutine($yielded)
+ {
+ $this->currentPromise = Create::promiseFor($yielded)
+ ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
+ }
+
+ /**
+ * @internal
+ */
+ public function _handleSuccess($value)
+ {
+ unset($this->currentPromise);
+ try {
+ $next = $this->generator->send($value);
+ if ($this->generator->valid()) {
+ $this->nextCoroutine($next);
+ } else {
+ $this->result->resolve($value);
+ }
+ } catch (Exception $exception) {
+ $this->result->reject($exception);
+ } catch (Throwable $throwable) {
+ $this->result->reject($throwable);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function _handleFailure($reason)
+ {
+ unset($this->currentPromise);
+ try {
+ $nextYield = $this->generator->throw(Create::exceptionFor($reason));
+ // The throw was caught, so keep iterating on the coroutine
+ $this->nextCoroutine($nextYield);
+ } catch (Exception $exception) {
+ $this->result->reject($exception);
+ } catch (Throwable $throwable) {
+ $this->result->reject($throwable);
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/Create.php b/vendor/guzzlehttp/promises/src/Create.php
new file mode 100644
index 0000000..8d038e9
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Create.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+final class Create
+{
+ /**
+ * Creates a promise for a value if the value is not a promise.
+ *
+ * @param mixed $value Promise or value.
+ *
+ * @return PromiseInterface
+ */
+ public static function promiseFor($value)
+ {
+ if ($value instanceof PromiseInterface) {
+ return $value;
+ }
+
+ // Return a Guzzle promise that shadows the given promise.
+ if (is_object($value) && method_exists($value, 'then')) {
+ $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
+ $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
+ $promise = new Promise($wfn, $cfn);
+ $value->then([$promise, 'resolve'], [$promise, 'reject']);
+ return $promise;
+ }
+
+ return new FulfilledPromise($value);
+ }
+
+ /**
+ * Creates a rejected promise for a reason if the reason is not a promise.
+ * If the provided reason is a promise, then it is returned as-is.
+ *
+ * @param mixed $reason Promise or reason.
+ *
+ * @return PromiseInterface
+ */
+ public static function rejectionFor($reason)
+ {
+ if ($reason instanceof PromiseInterface) {
+ return $reason;
+ }
+
+ return new RejectedPromise($reason);
+ }
+
+ /**
+ * Create an exception for a rejected promise value.
+ *
+ * @param mixed $reason
+ *
+ * @return \Exception|\Throwable
+ */
+ public static function exceptionFor($reason)
+ {
+ if ($reason instanceof \Exception || $reason instanceof \Throwable) {
+ return $reason;
+ }
+
+ return new RejectionException($reason);
+ }
+
+ /**
+ * Returns an iterator for the given value.
+ *
+ * @param mixed $value
+ *
+ * @return \Iterator
+ */
+ public static function iterFor($value)
+ {
+ if ($value instanceof \Iterator) {
+ return $value;
+ }
+
+ if (is_array($value)) {
+ return new \ArrayIterator($value);
+ }
+
+ return new \ArrayIterator([$value]);
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/Each.php b/vendor/guzzlehttp/promises/src/Each.php
new file mode 100644
index 0000000..1dda354
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Each.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+final class Each
+{
+ /**
+ * Given an iterator that yields promises or values, returns a promise that
+ * is fulfilled with a null value when the iterator has been consumed or
+ * the aggregate promise has been fulfilled or rejected.
+ *
+ * $onFulfilled is a function that accepts the fulfilled value, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary
+ * side effects and choose to resolve or reject the aggregate if needed.
+ *
+ * $onRejected is a function that accepts the rejection reason, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary
+ * side effects and choose to resolve or reject the aggregate if needed.
+ *
+ * @param mixed $iterable Iterator or array to iterate over.
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ */
+ public static function of(
+ $iterable,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected
+ ]))->promise();
+ }
+
+ /**
+ * Like of, but only allows a certain number of outstanding promises at any
+ * given time.
+ *
+ * $concurrency may be an integer or a function that accepts the number of
+ * pending promises and returns a numeric concurrency limit value to allow
+ * for dynamic a concurrency size.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ */
+ public static function ofLimit(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected,
+ 'concurrency' => $concurrency
+ ]))->promise();
+ }
+
+ /**
+ * Like limit, but ensures that no promise in the given $iterable argument
+ * is rejected. If any promise is rejected, then the aggregate promise is
+ * rejected with the encountered rejection.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ *
+ * @return PromiseInterface
+ */
+ public static function ofLimitAll(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null
+ ) {
+ return each_limit(
+ $iterable,
+ $concurrency,
+ $onFulfilled,
+ function ($reason, $idx, PromiseInterface $aggregate) {
+ $aggregate->reject($reason);
+ }
+ );
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/EachPromise.php b/vendor/guzzlehttp/promises/src/EachPromise.php
new file mode 100644
index 0000000..38ecb59
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/EachPromise.php
@@ -0,0 +1,255 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Represents a promise that iterates over many promises and invokes
+ * side-effect functions in the process.
+ */
+class EachPromise implements PromisorInterface
+{
+ private $pending = [];
+
+ private $nextPendingIndex = 0;
+
+ /** @var \Iterator|null */
+ private $iterable;
+
+ /** @var callable|int|null */
+ private $concurrency;
+
+ /** @var callable|null */
+ private $onFulfilled;
+
+ /** @var callable|null */
+ private $onRejected;
+
+ /** @var Promise|null */
+ private $aggregate;
+
+ /** @var bool|null */
+ private $mutex;
+
+ /**
+ * Configuration hash can include the following key value pairs:
+ *
+ * - fulfilled: (callable) Invoked when a promise fulfills. The function
+ * is invoked with three arguments: the fulfillment value, the index
+ * position from the iterable list of the promise, and the aggregate
+ * promise that manages all of the promises. The aggregate promise may
+ * be resolved from within the callback to short-circuit the promise.
+ * - rejected: (callable) Invoked when a promise is rejected. The
+ * function is invoked with three arguments: the rejection reason, the
+ * index position from the iterable list of the promise, and the
+ * aggregate promise that manages all of the promises. The aggregate
+ * promise may be resolved from within the callback to short-circuit
+ * the promise.
+ * - concurrency: (integer) Pass this configuration option to limit the
+ * allowed number of outstanding concurrently executing promises,
+ * creating a capped pool of promises. There is no limit by default.
+ *
+ * @param mixed $iterable Promises or values to iterate.
+ * @param array $config Configuration options
+ */
+ public function __construct($iterable, array $config = [])
+ {
+ $this->iterable = Create::iterFor($iterable);
+
+ if (isset($config['concurrency'])) {
+ $this->concurrency = $config['concurrency'];
+ }
+
+ if (isset($config['fulfilled'])) {
+ $this->onFulfilled = $config['fulfilled'];
+ }
+
+ if (isset($config['rejected'])) {
+ $this->onRejected = $config['rejected'];
+ }
+ }
+
+ /** @psalm-suppress InvalidNullableReturnType */
+ public function promise()
+ {
+ if ($this->aggregate) {
+ return $this->aggregate;
+ }
+
+ try {
+ $this->createPromise();
+ /** @psalm-assert Promise $this->aggregate */
+ $this->iterable->rewind();
+ $this->refillPending();
+ } catch (\Throwable $e) {
+ /**
+ * @psalm-suppress NullReference
+ * @phpstan-ignore-next-line
+ */
+ $this->aggregate->reject($e);
+ } catch (\Exception $e) {
+ /**
+ * @psalm-suppress NullReference
+ * @phpstan-ignore-next-line
+ */
+ $this->aggregate->reject($e);
+ }
+
+ /**
+ * @psalm-suppress NullableReturnStatement
+ * @phpstan-ignore-next-line
+ */
+ return $this->aggregate;
+ }
+
+ private function createPromise()
+ {
+ $this->mutex = false;
+ $this->aggregate = new Promise(function () {
+ if ($this->checkIfFinished()) {
+ return;
+ }
+ reset($this->pending);
+ // Consume a potentially fluctuating list of promises while
+ // ensuring that indexes are maintained (precluding array_shift).
+ while ($promise = current($this->pending)) {
+ next($this->pending);
+ $promise->wait();
+ if (Is::settled($this->aggregate)) {
+ return;
+ }
+ }
+ });
+
+ // Clear the references when the promise is resolved.
+ $clearFn = function () {
+ $this->iterable = $this->concurrency = $this->pending = null;
+ $this->onFulfilled = $this->onRejected = null;
+ $this->nextPendingIndex = 0;
+ };
+
+ $this->aggregate->then($clearFn, $clearFn);
+ }
+
+ private function refillPending()
+ {
+ if (!$this->concurrency) {
+ // Add all pending promises.
+ while ($this->addPending() && $this->advanceIterator());
+ return;
+ }
+
+ // Add only up to N pending promises.
+ $concurrency = is_callable($this->concurrency)
+ ? call_user_func($this->concurrency, count($this->pending))
+ : $this->concurrency;
+ $concurrency = max($concurrency - count($this->pending), 0);
+ // Concurrency may be set to 0 to disallow new promises.
+ if (!$concurrency) {
+ return;
+ }
+ // Add the first pending promise.
+ $this->addPending();
+ // Note this is special handling for concurrency=1 so that we do
+ // not advance the iterator after adding the first promise. This
+ // helps work around issues with generators that might not have the
+ // next value to yield until promise callbacks are called.
+ while (--$concurrency
+ && $this->advanceIterator()
+ && $this->addPending());
+ }
+
+ private function addPending()
+ {
+ if (!$this->iterable || !$this->iterable->valid()) {
+ return false;
+ }
+
+ $promise = Create::promiseFor($this->iterable->current());
+ $key = $this->iterable->key();
+
+ // Iterable keys may not be unique, so we use a counter to
+ // guarantee uniqueness
+ $idx = $this->nextPendingIndex++;
+
+ $this->pending[$idx] = $promise->then(
+ function ($value) use ($idx, $key) {
+ if ($this->onFulfilled) {
+ call_user_func(
+ $this->onFulfilled,
+ $value,
+ $key,
+ $this->aggregate
+ );
+ }
+ $this->step($idx);
+ },
+ function ($reason) use ($idx, $key) {
+ if ($this->onRejected) {
+ call_user_func(
+ $this->onRejected,
+ $reason,
+ $key,
+ $this->aggregate
+ );
+ }
+ $this->step($idx);
+ }
+ );
+
+ return true;
+ }
+
+ private function advanceIterator()
+ {
+ // Place a lock on the iterator so that we ensure to not recurse,
+ // preventing fatal generator errors.
+ if ($this->mutex) {
+ return false;
+ }
+
+ $this->mutex = true;
+
+ try {
+ $this->iterable->next();
+ $this->mutex = false;
+ return true;
+ } catch (\Throwable $e) {
+ $this->aggregate->reject($e);
+ $this->mutex = false;
+ return false;
+ } catch (\Exception $e) {
+ $this->aggregate->reject($e);
+ $this->mutex = false;
+ return false;
+ }
+ }
+
+ private function step($idx)
+ {
+ // If the promise was already resolved, then ignore this step.
+ if (Is::settled($this->aggregate)) {
+ return;
+ }
+
+ unset($this->pending[$idx]);
+
+ // Only refill pending promises if we are not locked, preventing the
+ // EachPromise to recursively invoke the provided iterator, which
+ // cause a fatal error: "Cannot resume an already running generator"
+ if ($this->advanceIterator() && !$this->checkIfFinished()) {
+ // Add more pending promises if possible.
+ $this->refillPending();
+ }
+ }
+
+ private function checkIfFinished()
+ {
+ if (!$this->pending && !$this->iterable->valid()) {
+ // Resolve the promise if there's nothing left to do.
+ $this->aggregate->resolve(null);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/FulfilledPromise.php b/vendor/guzzlehttp/promises/src/FulfilledPromise.php
new file mode 100644
index 0000000..98f72a6
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/FulfilledPromise.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise that has been fulfilled.
+ *
+ * Thenning off of this promise will invoke the onFulfilled callback
+ * immediately and ignore other callbacks.
+ */
+class FulfilledPromise implements PromiseInterface
+{
+ private $value;
+
+ public function __construct($value)
+ {
+ if (is_object($value) && method_exists($value, 'then')) {
+ throw new \InvalidArgumentException(
+ 'You cannot create a FulfilledPromise with a promise.'
+ );
+ }
+
+ $this->value = $value;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // Return itself if there is no onFulfilled function.
+ if (!$onFulfilled) {
+ return $this;
+ }
+
+ $queue = Utils::queue();
+ $p = new Promise([$queue, 'run']);
+ $value = $this->value;
+ $queue->add(static function () use ($p, $value, $onFulfilled) {
+ if (Is::pending($p)) {
+ try {
+ $p->resolve($onFulfilled($value));
+ } catch (\Throwable $e) {
+ $p->reject($e);
+ } catch (\Exception $e) {
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ return $unwrap ? $this->value : null;
+ }
+
+ public function getState()
+ {
+ return self::FULFILLED;
+ }
+
+ public function resolve($value)
+ {
+ if ($value !== $this->value) {
+ throw new \LogicException("Cannot resolve a fulfilled promise");
+ }
+ }
+
+ public function reject($reason)
+ {
+ throw new \LogicException("Cannot reject a fulfilled promise");
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/Is.php b/vendor/guzzlehttp/promises/src/Is.php
new file mode 100644
index 0000000..c3ed8d0
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Is.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+final class Is
+{
+ /**
+ * Returns true if a promise is pending.
+ *
+ * @return bool
+ */
+ public static function pending(PromiseInterface $promise)
+ {
+ return $promise->getState() === PromiseInterface::PENDING;
+ }
+
+ /**
+ * Returns true if a promise is fulfilled or rejected.
+ *
+ * @return bool
+ */
+ public static function settled(PromiseInterface $promise)
+ {
+ return $promise->getState() !== PromiseInterface::PENDING;
+ }
+
+ /**
+ * Returns true if a promise is fulfilled.
+ *
+ * @return bool
+ */
+ public static function fulfilled(PromiseInterface $promise)
+ {
+ return $promise->getState() === PromiseInterface::FULFILLED;
+ }
+
+ /**
+ * Returns true if a promise is rejected.
+ *
+ * @return bool
+ */
+ public static function rejected(PromiseInterface $promise)
+ {
+ return $promise->getState() === PromiseInterface::REJECTED;
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/Promise.php b/vendor/guzzlehttp/promises/src/Promise.php
new file mode 100644
index 0000000..7593905
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Promise.php
@@ -0,0 +1,278 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Promises/A+ implementation that avoids recursion when possible.
+ *
+ * @link https://promisesaplus.com/
+ */
+class Promise implements PromiseInterface
+{
+ private $state = self::PENDING;
+ private $result;
+ private $cancelFn;
+ private $waitFn;
+ private $waitList;
+ private $handlers = [];
+
+ /**
+ * @param callable $waitFn Fn that when invoked resolves the promise.
+ * @param callable $cancelFn Fn that when invoked cancels the promise.
+ */
+ public function __construct(
+ callable $waitFn = null,
+ callable $cancelFn = null
+ ) {
+ $this->waitFn = $waitFn;
+ $this->cancelFn = $cancelFn;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ if ($this->state === self::PENDING) {
+ $p = new Promise(null, [$this, 'cancel']);
+ $this->handlers[] = [$p, $onFulfilled, $onRejected];
+ $p->waitList = $this->waitList;
+ $p->waitList[] = $this;
+ return $p;
+ }
+
+ // Return a fulfilled promise and immediately invoke any callbacks.
+ if ($this->state === self::FULFILLED) {
+ $promise = Create::promiseFor($this->result);
+ return $onFulfilled ? $promise->then($onFulfilled) : $promise;
+ }
+
+ // It's either cancelled or rejected, so return a rejected promise
+ // and immediately invoke any callbacks.
+ $rejection = Create::rejectionFor($this->result);
+ return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true)
+ {
+ $this->waitIfPending();
+
+ if ($this->result instanceof PromiseInterface) {
+ return $this->result->wait($unwrap);
+ }
+ if ($unwrap) {
+ if ($this->state === self::FULFILLED) {
+ return $this->result;
+ }
+ // It's rejected so "unwrap" and throw an exception.
+ throw Create::exceptionFor($this->result);
+ }
+ }
+
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ public function cancel()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ }
+
+ $this->waitFn = $this->waitList = null;
+
+ if ($this->cancelFn) {
+ $fn = $this->cancelFn;
+ $this->cancelFn = null;
+ try {
+ $fn();
+ } catch (\Throwable $e) {
+ $this->reject($e);
+ } catch (\Exception $e) {
+ $this->reject($e);
+ }
+ }
+
+ // Reject the promise only if it wasn't rejected in a then callback.
+ /** @psalm-suppress RedundantCondition */
+ if ($this->state === self::PENDING) {
+ $this->reject(new CancellationException('Promise has been cancelled'));
+ }
+ }
+
+ public function resolve($value)
+ {
+ $this->settle(self::FULFILLED, $value);
+ }
+
+ public function reject($reason)
+ {
+ $this->settle(self::REJECTED, $reason);
+ }
+
+ private function settle($state, $value)
+ {
+ if ($this->state !== self::PENDING) {
+ // Ignore calls with the same resolution.
+ if ($state === $this->state && $value === $this->result) {
+ return;
+ }
+ throw $this->state === $state
+ ? new \LogicException("The promise is already {$state}.")
+ : new \LogicException("Cannot change a {$this->state} promise to {$state}");
+ }
+
+ if ($value === $this) {
+ throw new \LogicException('Cannot fulfill or reject a promise with itself');
+ }
+
+ // Clear out the state of the promise but stash the handlers.
+ $this->state = $state;
+ $this->result = $value;
+ $handlers = $this->handlers;
+ $this->handlers = null;
+ $this->waitList = $this->waitFn = null;
+ $this->cancelFn = null;
+
+ if (!$handlers) {
+ return;
+ }
+
+ // If the value was not a settled promise or a thenable, then resolve
+ // it in the task queue using the correct ID.
+ if (!is_object($value) || !method_exists($value, 'then')) {
+ $id = $state === self::FULFILLED ? 1 : 2;
+ // It's a success, so resolve the handlers in the queue.
+ Utils::queue()->add(static function () use ($id, $value, $handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler($id, $value, $handler);
+ }
+ });
+ } elseif ($value instanceof Promise && Is::pending($value)) {
+ // We can just merge our handlers onto the next promise.
+ $value->handlers = array_merge($value->handlers, $handlers);
+ } else {
+ // Resolve the handlers when the forwarded promise is resolved.
+ $value->then(
+ static function ($value) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(1, $value, $handler);
+ }
+ },
+ static function ($reason) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(2, $reason, $handler);
+ }
+ }
+ );
+ }
+ }
+
+ /**
+ * Call a stack of handlers using a specific callback index and value.
+ *
+ * @param int $index 1 (resolve) or 2 (reject).
+ * @param mixed $value Value to pass to the callback.
+ * @param array $handler Array of handler data (promise and callbacks).
+ */
+ private static function callHandler($index, $value, array $handler)
+ {
+ /** @var PromiseInterface $promise */
+ $promise = $handler[0];
+
+ // The promise may have been cancelled or resolved before placing
+ // this thunk in the queue.
+ if (Is::settled($promise)) {
+ return;
+ }
+
+ try {
+ if (isset($handler[$index])) {
+ /*
+ * If $f throws an exception, then $handler will be in the exception
+ * stack trace. Since $handler contains a reference to the callable
+ * itself we get a circular reference. We clear the $handler
+ * here to avoid that memory leak.
+ */
+ $f = $handler[$index];
+ unset($handler);
+ $promise->resolve($f($value));
+ } elseif ($index === 1) {
+ // Forward resolution values as-is.
+ $promise->resolve($value);
+ } else {
+ // Forward rejections down the chain.
+ $promise->reject($value);
+ }
+ } catch (\Throwable $reason) {
+ $promise->reject($reason);
+ } catch (\Exception $reason) {
+ $promise->reject($reason);
+ }
+ }
+
+ private function waitIfPending()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ } elseif ($this->waitFn) {
+ $this->invokeWaitFn();
+ } elseif ($this->waitList) {
+ $this->invokeWaitList();
+ } else {
+ // If there's no wait function, then reject the promise.
+ $this->reject('Cannot wait on a promise that has '
+ . 'no internal wait function. You must provide a wait '
+ . 'function when constructing the promise to be able to '
+ . 'wait on a promise.');
+ }
+
+ Utils::queue()->run();
+
+ /** @psalm-suppress RedundantCondition */
+ if ($this->state === self::PENDING) {
+ $this->reject('Invoking the wait callback did not resolve the promise');
+ }
+ }
+
+ private function invokeWaitFn()
+ {
+ try {
+ $wfn = $this->waitFn;
+ $this->waitFn = null;
+ $wfn(true);
+ } catch (\Exception $reason) {
+ if ($this->state === self::PENDING) {
+ // The promise has not been resolved yet, so reject the promise
+ // with the exception.
+ $this->reject($reason);
+ } else {
+ // The promise was already resolved, so there's a problem in
+ // the application.
+ throw $reason;
+ }
+ }
+ }
+
+ private function invokeWaitList()
+ {
+ $waitList = $this->waitList;
+ $this->waitList = null;
+
+ foreach ($waitList as $result) {
+ do {
+ $result->waitIfPending();
+ $result = $result->result;
+ } while ($result instanceof Promise);
+
+ if ($result instanceof PromiseInterface) {
+ $result->wait(false);
+ }
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/PromiseInterface.php b/vendor/guzzlehttp/promises/src/PromiseInterface.php
new file mode 100644
index 0000000..e598331
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/PromiseInterface.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise represents the eventual result of an asynchronous operation.
+ *
+ * The primary way of interacting with a promise is through its then method,
+ * which registers callbacks to receive either a promise’s eventual value or
+ * the reason why the promise cannot be fulfilled.
+ *
+ * @link https://promisesaplus.com/
+ */
+interface PromiseInterface
+{
+ const PENDING = 'pending';
+ const FULFILLED = 'fulfilled';
+ const REJECTED = 'rejected';
+
+ /**
+ * Appends fulfillment and rejection handlers to the promise, and returns
+ * a new promise resolving to the return value of the called handler.
+ *
+ * @param callable $onFulfilled Invoked when the promise fulfills.
+ * @param callable $onRejected Invoked when the promise is rejected.
+ *
+ * @return PromiseInterface
+ */
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ );
+
+ /**
+ * Appends a rejection handler callback to the promise, and returns a new
+ * promise resolving to the return value of the callback if it is called,
+ * or to its original fulfillment value if the promise is instead
+ * fulfilled.
+ *
+ * @param callable $onRejected Invoked when the promise is rejected.
+ *
+ * @return PromiseInterface
+ */
+ public function otherwise(callable $onRejected);
+
+ /**
+ * Get the state of the promise ("pending", "rejected", or "fulfilled").
+ *
+ * The three states can be checked against the constants defined on
+ * PromiseInterface: PENDING, FULFILLED, and REJECTED.
+ *
+ * @return string
+ */
+ public function getState();
+
+ /**
+ * Resolve the promise with the given value.
+ *
+ * @param mixed $value
+ *
+ * @throws \RuntimeException if the promise is already resolved.
+ */
+ public function resolve($value);
+
+ /**
+ * Reject the promise with the given reason.
+ *
+ * @param mixed $reason
+ *
+ * @throws \RuntimeException if the promise is already resolved.
+ */
+ public function reject($reason);
+
+ /**
+ * Cancels the promise if possible.
+ *
+ * @link https://github.com/promises-aplus/cancellation-spec/issues/7
+ */
+ public function cancel();
+
+ /**
+ * Waits until the promise completes if possible.
+ *
+ * Pass $unwrap as true to unwrap the result of the promise, either
+ * returning the resolved value or throwing the rejected exception.
+ *
+ * If the promise cannot be waited on, then the promise will be rejected.
+ *
+ * @param bool $unwrap
+ *
+ * @return mixed
+ *
+ * @throws \LogicException if the promise has no wait function or if the
+ * promise does not settle after waiting.
+ */
+ public function wait($unwrap = true);
+}
diff --git a/vendor/guzzlehttp/promises/src/PromisorInterface.php b/vendor/guzzlehttp/promises/src/PromisorInterface.php
new file mode 100644
index 0000000..2d2e342
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/PromisorInterface.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Interface used with classes that return a promise.
+ */
+interface PromisorInterface
+{
+ /**
+ * Returns a promise.
+ *
+ * @return PromiseInterface
+ */
+ public function promise();
+}
diff --git a/vendor/guzzlehttp/promises/src/RejectedPromise.php b/vendor/guzzlehttp/promises/src/RejectedPromise.php
new file mode 100644
index 0000000..d291846
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/RejectedPromise.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A promise that has been rejected.
+ *
+ * Thenning off of this promise will invoke the onRejected callback
+ * immediately and ignore other callbacks.
+ */
+class RejectedPromise implements PromiseInterface
+{
+ private $reason;
+
+ public function __construct($reason)
+ {
+ if (is_object($reason) && method_exists($reason, 'then')) {
+ throw new \InvalidArgumentException(
+ 'You cannot create a RejectedPromise with a promise.'
+ );
+ }
+
+ $this->reason = $reason;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // If there's no onRejected callback then just return self.
+ if (!$onRejected) {
+ return $this;
+ }
+
+ $queue = Utils::queue();
+ $reason = $this->reason;
+ $p = new Promise([$queue, 'run']);
+ $queue->add(static function () use ($p, $reason, $onRejected) {
+ if (Is::pending($p)) {
+ try {
+ // Return a resolved promise if onRejected does not throw.
+ $p->resolve($onRejected($reason));
+ } catch (\Throwable $e) {
+ // onRejected threw, so return a rejected promise.
+ $p->reject($e);
+ } catch (\Exception $e) {
+ // onRejected threw, so return a rejected promise.
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ if ($unwrap) {
+ throw Create::exceptionFor($this->reason);
+ }
+
+ return null;
+ }
+
+ public function getState()
+ {
+ return self::REJECTED;
+ }
+
+ public function resolve($value)
+ {
+ throw new \LogicException("Cannot resolve a rejected promise");
+ }
+
+ public function reject($reason)
+ {
+ if ($reason !== $this->reason) {
+ throw new \LogicException("Cannot reject a rejected promise");
+ }
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/RejectionException.php b/vendor/guzzlehttp/promises/src/RejectionException.php
new file mode 100644
index 0000000..e2f1377
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/RejectionException.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A special exception that is thrown when waiting on a rejected promise.
+ *
+ * The reason value is available via the getReason() method.
+ */
+class RejectionException extends \RuntimeException
+{
+ /** @var mixed Rejection reason. */
+ private $reason;
+
+ /**
+ * @param mixed $reason Rejection reason.
+ * @param string $description Optional description
+ */
+ public function __construct($reason, $description = null)
+ {
+ $this->reason = $reason;
+
+ $message = 'The promise was rejected';
+
+ if ($description) {
+ $message .= ' with reason: ' . $description;
+ } elseif (is_string($reason)
+ || (is_object($reason) && method_exists($reason, '__toString'))
+ ) {
+ $message .= ' with reason: ' . $this->reason;
+ } elseif ($reason instanceof \JsonSerializable) {
+ $message .= ' with reason: '
+ . json_encode($this->reason, JSON_PRETTY_PRINT);
+ }
+
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns the rejection reason.
+ *
+ * @return mixed
+ */
+ public function getReason()
+ {
+ return $this->reason;
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/TaskQueue.php b/vendor/guzzlehttp/promises/src/TaskQueue.php
new file mode 100644
index 0000000..f0fba2c
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/TaskQueue.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * A task queue that executes tasks in a FIFO order.
+ *
+ * This task queue class is used to settle promises asynchronously and
+ * maintains a constant stack size. You can use the task queue asynchronously
+ * by calling the `run()` function of the global task queue in an event loop.
+ *
+ * GuzzleHttp\Promise\Utils::queue()->run();
+ */
+class TaskQueue implements TaskQueueInterface
+{
+ private $enableShutdown = true;
+ private $queue = [];
+
+ public function __construct($withShutdown = true)
+ {
+ if ($withShutdown) {
+ register_shutdown_function(function () {
+ if ($this->enableShutdown) {
+ // Only run the tasks if an E_ERROR didn't occur.
+ $err = error_get_last();
+ if (!$err || ($err['type'] ^ E_ERROR)) {
+ $this->run();
+ }
+ }
+ });
+ }
+ }
+
+ public function isEmpty()
+ {
+ return !$this->queue;
+ }
+
+ public function add(callable $task)
+ {
+ $this->queue[] = $task;
+ }
+
+ public function run()
+ {
+ while ($task = array_shift($this->queue)) {
+ /** @var callable $task */
+ $task();
+ }
+ }
+
+ /**
+ * The task queue will be run and exhausted by default when the process
+ * exits IFF the exit is not the result of a PHP E_ERROR error.
+ *
+ * You can disable running the automatic shutdown of the queue by calling
+ * this function. If you disable the task queue shutdown process, then you
+ * MUST either run the task queue (as a result of running your event loop
+ * or manually using the run() method) or wait on each outstanding promise.
+ *
+ * Note: This shutdown will occur before any destructors are triggered.
+ */
+ public function disableShutdown()
+ {
+ $this->enableShutdown = false;
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/TaskQueueInterface.php b/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
new file mode 100644
index 0000000..723d4d5
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+interface TaskQueueInterface
+{
+ /**
+ * Returns true if the queue is empty.
+ *
+ * @return bool
+ */
+ public function isEmpty();
+
+ /**
+ * Adds a task to the queue that will be executed the next time run is
+ * called.
+ */
+ public function add(callable $task);
+
+ /**
+ * Execute all of the pending task in the queue.
+ */
+ public function run();
+}
diff --git a/vendor/guzzlehttp/promises/src/Utils.php b/vendor/guzzlehttp/promises/src/Utils.php
new file mode 100644
index 0000000..8647126
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/Utils.php
@@ -0,0 +1,276 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+final class Utils
+{
+ /**
+ * Get the global task queue used for promise resolution.
+ *
+ * This task queue MUST be run in an event loop in order for promises to be
+ * settled asynchronously. It will be automatically run when synchronously
+ * waiting on a promise.
+ *
+ * <code>
+ * while ($eventLoop->isRunning()) {
+ * GuzzleHttp\Promise\Utils::queue()->run();
+ * }
+ * </code>
+ *
+ * @param TaskQueueInterface $assign Optionally specify a new queue instance.
+ *
+ * @return TaskQueueInterface
+ */
+ public static function queue(TaskQueueInterface $assign = null)
+ {
+ static $queue;
+
+ if ($assign) {
+ $queue = $assign;
+ } elseif (!$queue) {
+ $queue = new TaskQueue();
+ }
+
+ return $queue;
+ }
+
+ /**
+ * Adds a function to run in the task queue when it is next `run()` and
+ * returns a promise that is fulfilled or rejected with the result.
+ *
+ * @param callable $task Task function to run.
+ *
+ * @return PromiseInterface
+ */
+ public static function task(callable $task)
+ {
+ $queue = self::queue();
+ $promise = new Promise([$queue, 'run']);
+ $queue->add(function () use ($task, $promise) {
+ try {
+ if (Is::pending($promise)) {
+ $promise->resolve($task());
+ }
+ } catch (\Throwable $e) {
+ $promise->reject($e);
+ } catch (\Exception $e) {
+ $promise->reject($e);
+ }
+ });
+
+ return $promise;
+ }
+
+ /**
+ * Synchronously waits on a promise to resolve and returns an inspection
+ * state array.
+ *
+ * Returns a state associative array containing a "state" key mapping to a
+ * valid promise state. If the state of the promise is "fulfilled", the
+ * array will contain a "value" key mapping to the fulfilled value of the
+ * promise. If the promise is rejected, the array will contain a "reason"
+ * key mapping to the rejection reason of the promise.
+ *
+ * @param PromiseInterface $promise Promise or value.
+ *
+ * @return array
+ */
+ public static function inspect(PromiseInterface $promise)
+ {
+ try {
+ return [
+ 'state' => PromiseInterface::FULFILLED,
+ 'value' => $promise->wait()
+ ];
+ } catch (RejectionException $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
+ } catch (\Throwable $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
+ } catch (\Exception $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
+ }
+ }
+
+ /**
+ * Waits on all of the provided promises, but does not unwrap rejected
+ * promises as thrown exception.
+ *
+ * Returns an array of inspection state arrays.
+ *
+ * @see inspect for the inspection state array format.
+ *
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
+ *
+ * @return array
+ */
+ public static function inspectAll($promises)
+ {
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = inspect($promise);
+ }
+
+ return $results;
+ }
+
+ /**
+ * Waits on all of the provided promises and returns the fulfilled values.
+ *
+ * Returns an array that contains the value of each promise (in the same
+ * order the promises were provided). An exception is thrown if any of the
+ * promises are rejected.
+ *
+ * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
+ *
+ * @return array
+ *
+ * @throws \Exception on error
+ * @throws \Throwable on error in PHP >=7
+ */
+ public static function unwrap($promises)
+ {
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = $promise->wait();
+ }
+
+ return $results;
+ }
+
+ /**
+ * Given an array of promises, return a promise that is fulfilled when all
+ * the items in the array are fulfilled.
+ *
+ * The promise's fulfillment value is an array with fulfillment values at
+ * respective positions to the original array. If any promise in the array
+ * rejects, the returned promise is rejected with the rejection reason.
+ *
+ * @param mixed $promises Promises or values.
+ * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
+ *
+ * @return PromiseInterface
+ */
+ public static function all($promises, $recursive = false)
+ {
+ $results = [];
+ $promise = Each::of(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = $value;
+ },
+ function ($reason, $idx, Promise $aggregate) {
+ $aggregate->reject($reason);
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+
+ if (true === $recursive) {
+ $promise = $promise->then(function ($results) use ($recursive, &$promises) {
+ foreach ($promises as $promise) {
+ if (Is::pending($promise)) {
+ return self::all($promises, $recursive);
+ }
+ }
+ return $results;
+ });
+ }
+
+ return $promise;
+ }
+
+ /**
+ * Initiate a competitive race between multiple promises or values (values
+ * will become immediately fulfilled promises).
+ *
+ * When count amount of promises have been fulfilled, the returned promise
+ * is fulfilled with an array that contains the fulfillment values of the
+ * winners in order of resolution.
+ *
+ * This promise is rejected with a {@see AggregateException} if the number
+ * of fulfilled promises is less than the desired $count.
+ *
+ * @param int $count Total number of promises.
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+ public static function some($count, $promises)
+ {
+ $results = [];
+ $rejections = [];
+
+ return Each::of(
+ $promises,
+ function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
+ if (Is::settled($p)) {
+ return;
+ }
+ $results[$idx] = $value;
+ if (count($results) >= $count) {
+ $p->resolve(null);
+ }
+ },
+ function ($reason) use (&$rejections) {
+ $rejections[] = $reason;
+ }
+ )->then(
+ function () use (&$results, &$rejections, $count) {
+ if (count($results) !== $count) {
+ throw new AggregateException(
+ 'Not enough promises to fulfill count',
+ $rejections
+ );
+ }
+ ksort($results);
+ return array_values($results);
+ }
+ );
+ }
+
+ /**
+ * Like some(), with 1 as count. However, if the promise fulfills, the
+ * fulfillment value is not an array of 1 but the value directly.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+ public static function any($promises)
+ {
+ return self::some(1, $promises)->then(function ($values) {
+ return $values[0];
+ });
+ }
+
+ /**
+ * Returns a promise that is fulfilled when all of the provided promises have
+ * been fulfilled or rejected.
+ *
+ * The returned promise is fulfilled with an array of inspection state arrays.
+ *
+ * @see inspect for the inspection state array format.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+ public static function settle($promises)
+ {
+ $results = [];
+
+ return Each::of(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
+ },
+ function ($reason, $idx) use (&$results) {
+ $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+ }
+}
diff --git a/vendor/guzzlehttp/promises/src/functions.php b/vendor/guzzlehttp/promises/src/functions.php
new file mode 100644
index 0000000..c03d39d
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/functions.php
@@ -0,0 +1,363 @@
+<?php
+
+namespace GuzzleHttp\Promise;
+
+/**
+ * Get the global task queue used for promise resolution.
+ *
+ * This task queue MUST be run in an event loop in order for promises to be
+ * settled asynchronously. It will be automatically run when synchronously
+ * waiting on a promise.
+ *
+ * <code>
+ * while ($eventLoop->isRunning()) {
+ * GuzzleHttp\Promise\queue()->run();
+ * }
+ * </code>
+ *
+ * @param TaskQueueInterface $assign Optionally specify a new queue instance.
+ *
+ * @return TaskQueueInterface
+ *
+ * @deprecated queue will be removed in guzzlehttp/promises:2.0. Use Utils::queue instead.
+ */
+function queue(TaskQueueInterface $assign = null)
+{
+ return Utils::queue($assign);
+}
+
+/**
+ * Adds a function to run in the task queue when it is next `run()` and returns
+ * a promise that is fulfilled or rejected with the result.
+ *
+ * @param callable $task Task function to run.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated task will be removed in guzzlehttp/promises:2.0. Use Utils::task instead.
+ */
+function task(callable $task)
+{
+ return Utils::task($task);
+}
+
+/**
+ * Creates a promise for a value if the value is not a promise.
+ *
+ * @param mixed $value Promise or value.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated promise_for will be removed in guzzlehttp/promises:2.0. Use Create::promiseFor instead.
+ */
+function promise_for($value)
+{
+ return Create::promiseFor($value);
+}
+
+/**
+ * Creates a rejected promise for a reason if the reason is not a promise. If
+ * the provided reason is a promise, then it is returned as-is.
+ *
+ * @param mixed $reason Promise or reason.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead.
+ */
+function rejection_for($reason)
+{
+ return Create::rejectionFor($reason);
+}
+
+/**
+ * Create an exception for a rejected promise value.
+ *
+ * @param mixed $reason
+ *
+ * @return \Exception|\Throwable
+ *
+ * @deprecated exception_for will be removed in guzzlehttp/promises:2.0. Use Create::exceptionFor instead.
+ */
+function exception_for($reason)
+{
+ return Create::exceptionFor($reason);
+}
+
+/**
+ * Returns an iterator for the given value.
+ *
+ * @param mixed $value
+ *
+ * @return \Iterator
+ *
+ * @deprecated iter_for will be removed in guzzlehttp/promises:2.0. Use Create::iterFor instead.
+ */
+function iter_for($value)
+{
+ return Create::iterFor($value);
+}
+
+/**
+ * Synchronously waits on a promise to resolve and returns an inspection state
+ * array.
+ *
+ * Returns a state associative array containing a "state" key mapping to a
+ * valid promise state. If the state of the promise is "fulfilled", the array
+ * will contain a "value" key mapping to the fulfilled value of the promise. If
+ * the promise is rejected, the array will contain a "reason" key mapping to
+ * the rejection reason of the promise.
+ *
+ * @param PromiseInterface $promise Promise or value.
+ *
+ * @return array
+ *
+ * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspect instead.
+ */
+function inspect(PromiseInterface $promise)
+{
+ return Utils::inspect($promise);
+}
+
+/**
+ * Waits on all of the provided promises, but does not unwrap rejected promises
+ * as thrown exception.
+ *
+ * Returns an array of inspection state arrays.
+ *
+ * @see inspect for the inspection state array format.
+ *
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
+ *
+ * @return array
+ *
+ * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspectAll instead.
+ */
+function inspect_all($promises)
+{
+ return Utils::inspectAll($promises);
+}
+
+/**
+ * Waits on all of the provided promises and returns the fulfilled values.
+ *
+ * Returns an array that contains the value of each promise (in the same order
+ * the promises were provided). An exception is thrown if any of the promises
+ * are rejected.
+ *
+ * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
+ *
+ * @return array
+ *
+ * @throws \Exception on error
+ * @throws \Throwable on error in PHP >=7
+ *
+ * @deprecated unwrap will be removed in guzzlehttp/promises:2.0. Use Utils::unwrap instead.
+ */
+function unwrap($promises)
+{
+ return Utils::unwrap($promises);
+}
+
+/**
+ * Given an array of promises, return a promise that is fulfilled when all the
+ * items in the array are fulfilled.
+ *
+ * The promise's fulfillment value is an array with fulfillment values at
+ * respective positions to the original array. If any promise in the array
+ * rejects, the returned promise is rejected with the rejection reason.
+ *
+ * @param mixed $promises Promises or values.
+ * @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated all will be removed in guzzlehttp/promises:2.0. Use Utils::all instead.
+ */
+function all($promises, $recursive = false)
+{
+ return Utils::all($promises, $recursive);
+}
+
+/**
+ * Initiate a competitive race between multiple promises or values (values will
+ * become immediately fulfilled promises).
+ *
+ * When count amount of promises have been fulfilled, the returned promise is
+ * fulfilled with an array that contains the fulfillment values of the winners
+ * in order of resolution.
+ *
+ * This promise is rejected with a {@see AggregateException} if the number of
+ * fulfilled promises is less than the desired $count.
+ *
+ * @param int $count Total number of promises.
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated some will be removed in guzzlehttp/promises:2.0. Use Utils::some instead.
+ */
+function some($count, $promises)
+{
+ return Utils::some($count, $promises);
+}
+
+/**
+ * Like some(), with 1 as count. However, if the promise fulfills, the
+ * fulfillment value is not an array of 1 but the value directly.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated any will be removed in guzzlehttp/promises:2.0. Use Utils::any instead.
+ */
+function any($promises)
+{
+ return Utils::any($promises);
+}
+
+/**
+ * Returns a promise that is fulfilled when all of the provided promises have
+ * been fulfilled or rejected.
+ *
+ * The returned promise is fulfilled with an array of inspection state arrays.
+ *
+ * @see inspect for the inspection state array format.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated settle will be removed in guzzlehttp/promises:2.0. Use Utils::settle instead.
+ */
+function settle($promises)
+{
+ return Utils::settle($promises);
+}
+
+/**
+ * Given an iterator that yields promises or values, returns a promise that is
+ * fulfilled with a null value when the iterator has been consumed or the
+ * aggregate promise has been fulfilled or rejected.
+ *
+ * $onFulfilled is a function that accepts the fulfilled value, iterator index,
+ * and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate if needed.
+ *
+ * $onRejected is a function that accepts the rejection reason, iterator index,
+ * and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate if needed.
+ *
+ * @param mixed $iterable Iterator or array to iterate over.
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated each will be removed in guzzlehttp/promises:2.0. Use Each::of instead.
+ */
+function each(
+ $iterable,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return Each::of($iterable, $onFulfilled, $onRejected);
+}
+
+/**
+ * Like each, but only allows a certain number of outstanding promises at any
+ * given time.
+ *
+ * $concurrency may be an integer or a function that accepts the number of
+ * pending promises and returns a numeric concurrency limit value to allow for
+ * dynamic a concurrency size.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated each_limit will be removed in guzzlehttp/promises:2.0. Use Each::ofLimit instead.
+ */
+function each_limit(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected);
+}
+
+/**
+ * Like each_limit, but ensures that no promise in the given $iterable argument
+ * is rejected. If any promise is rejected, then the aggregate promise is
+ * rejected with the encountered rejection.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated each_limit_all will be removed in guzzlehttp/promises:2.0. Use Each::ofLimitAll instead.
+ */
+function each_limit_all(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null
+) {
+ return Each::ofLimitAll($iterable, $concurrency, $onFulfilled);
+}
+
+/**
+ * Returns true if a promise is fulfilled.
+ *
+ * @return bool
+ *
+ * @deprecated is_fulfilled will be removed in guzzlehttp/promises:2.0. Use Is::fulfilled instead.
+ */
+function is_fulfilled(PromiseInterface $promise)
+{
+ return Is::fulfilled($promise);
+}
+
+/**
+ * Returns true if a promise is rejected.
+ *
+ * @return bool
+ *
+ * @deprecated is_rejected will be removed in guzzlehttp/promises:2.0. Use Is::rejected instead.
+ */
+function is_rejected(PromiseInterface $promise)
+{
+ return Is::rejected($promise);
+}
+
+/**
+ * Returns true if a promise is fulfilled or rejected.
+ *
+ * @return bool
+ *
+ * @deprecated is_settled will be removed in guzzlehttp/promises:2.0. Use Is::settled instead.
+ */
+function is_settled(PromiseInterface $promise)
+{
+ return Is::settled($promise);
+}
+
+/**
+ * Create a new coroutine.
+ *
+ * @see Coroutine
+ *
+ * @return PromiseInterface
+ *
+ * @deprecated coroutine will be removed in guzzlehttp/promises:2.0. Use Coroutine::of instead.
+ */
+function coroutine(callable $generatorFn)
+{
+ return Coroutine::of($generatorFn);
+}
diff --git a/vendor/guzzlehttp/promises/src/functions_include.php b/vendor/guzzlehttp/promises/src/functions_include.php
new file mode 100644
index 0000000..34cd171
--- /dev/null
+++ b/vendor/guzzlehttp/promises/src/functions_include.php
@@ -0,0 +1,6 @@
+<?php
+
+// Don't redefine the functions if included multiple times.
+if (!function_exists('GuzzleHttp\Promise\promise_for')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/guzzlehttp/psr7/LICENSE b/vendor/guzzlehttp/psr7/LICENSE
new file mode 100644
index 0000000..51c7ec8
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/LICENSE
@@ -0,0 +1,26 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Michael Dowling <mtdowling@gmail.com>
+Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>
+Copyright (c) 2015 Graham Campbell <hello@gjcampbell.co.uk>
+Copyright (c) 2016 Tobias Schultze <webmaster@tubo-world.de>
+Copyright (c) 2016 George Mponos <gmponos@gmail.com>
+Copyright (c) 2018 Tobias Nyholm <tobias.nyholm@gmail.com>
+
+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/guzzlehttp/psr7/composer.json b/vendor/guzzlehttp/psr7/composer.json
new file mode 100644
index 0000000..7ecdc8b
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/composer.json
@@ -0,0 +1,76 @@
+{
+ "name": "guzzlehttp/psr7",
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": ["request", "response", "message", "stream", "http", "uri", "url", "psr-7"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10",
+ "ext-zlib": "*"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "suggest": {
+ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GuzzleHttp\\Tests\\Psr7\\": "tests/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.7-dev"
+ }
+ },
+ "config": {
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "bamarni/composer-bin-plugin": true
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/AppendStream.php b/vendor/guzzlehttp/psr7/src/AppendStream.php
new file mode 100644
index 0000000..fa9153d
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/AppendStream.php
@@ -0,0 +1,246 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Reads from multiple streams, one after the other.
+ *
+ * This is a read-only stream decorator.
+ *
+ * @final
+ */
+class AppendStream implements StreamInterface
+{
+ /** @var StreamInterface[] Streams being decorated */
+ private $streams = [];
+
+ private $seekable = true;
+ private $current = 0;
+ private $pos = 0;
+
+ /**
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
+ * be readable.
+ */
+ public function __construct(array $streams = [])
+ {
+ foreach ($streams as $stream) {
+ $this->addStream($stream);
+ }
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ /**
+ * Add a stream to the AppendStream
+ *
+ * @param StreamInterface $stream Stream to append. Must be readable.
+ *
+ * @throws \InvalidArgumentException if the stream is not readable
+ */
+ public function addStream(StreamInterface $stream)
+ {
+ if (!$stream->isReadable()) {
+ throw new \InvalidArgumentException('Each stream must be readable');
+ }
+
+ // The stream is only seekable if all streams are seekable
+ if (!$stream->isSeekable()) {
+ $this->seekable = false;
+ }
+
+ $this->streams[] = $stream;
+ }
+
+ public function getContents()
+ {
+ return Utils::copyToString($this);
+ }
+
+ /**
+ * Closes each attached stream.
+ *
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->close();
+ }
+
+ $this->streams = [];
+ }
+
+ /**
+ * Detaches each attached stream.
+ *
+ * Returns null as it's not clear which underlying stream resource to return.
+ *
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->detach();
+ }
+
+ $this->streams = [];
+
+ return null;
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Tries to calculate the size by adding the size of each stream.
+ *
+ * If any of the streams do not return a valid number, then the size of the
+ * append stream cannot be determined and null is returned.
+ *
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ $size = 0;
+
+ foreach ($this->streams as $stream) {
+ $s = $stream->getSize();
+ if ($s === null) {
+ return null;
+ }
+ $size += $s;
+ }
+
+ return $size;
+ }
+
+ public function eof()
+ {
+ return !$this->streams ||
+ ($this->current >= count($this->streams) - 1 &&
+ $this->streams[$this->current]->eof());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ /**
+ * Attempts to seek to the given position. Only supports SEEK_SET.
+ *
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('This AppendStream is not seekable');
+ } elseif ($whence !== SEEK_SET) {
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
+ }
+
+ $this->pos = $this->current = 0;
+
+ // Rewind each stream
+ foreach ($this->streams as $i => $stream) {
+ try {
+ $stream->rewind();
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Unable to seek stream '
+ . $i . ' of the AppendStream', 0, $e);
+ }
+ }
+
+ // Seek to the actual position by reading from each stream
+ while ($this->pos < $offset && !$this->eof()) {
+ $result = $this->read(min(8096, $offset - $this->pos));
+ if ($result === '') {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads from all of the appended streams until the length is met or EOF.
+ *
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ $buffer = '';
+ $total = count($this->streams) - 1;
+ $remaining = $length;
+ $progressToNext = false;
+
+ while ($remaining > 0) {
+
+ // Progress to the next stream if needed.
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
+ $progressToNext = false;
+ if ($this->current === $total) {
+ break;
+ }
+ $this->current++;
+ }
+
+ $result = $this->streams[$this->current]->read($remaining);
+
+ // Using a loose comparison here to match on '', false, and null
+ if ($result == null) {
+ $progressToNext = true;
+ continue;
+ }
+
+ $buffer .= $result;
+ $remaining = $length - strlen($buffer);
+ }
+
+ $this->pos += strlen($buffer);
+
+ return $buffer;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to an AppendStream');
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key ? null : [];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/BufferStream.php b/vendor/guzzlehttp/psr7/src/BufferStream.php
new file mode 100644
index 0000000..783859c
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/BufferStream.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a buffer stream that can be written to to fill a buffer, and read
+ * from to remove bytes from the buffer.
+ *
+ * This stream returns a "hwm" metadata value that tells upstream consumers
+ * what the configured high water mark of the stream is, or the maximum
+ * preferred size of the buffer.
+ *
+ * @final
+ */
+class BufferStream implements StreamInterface
+{
+ private $hwm;
+ private $buffer = '';
+
+ /**
+ * @param int $hwm High water mark, representing the preferred maximum
+ * buffer size. If the size of the buffer exceeds the high
+ * water mark, then calls to write will continue to succeed
+ * but will return false to inform writers to slow down
+ * until the buffer has been drained by reading from it.
+ */
+ public function __construct($hwm = 16384)
+ {
+ $this->hwm = $hwm;
+ }
+
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ public function getContents()
+ {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ }
+
+ public function detach()
+ {
+ $this->close();
+
+ return null;
+ }
+
+ public function getSize()
+ {
+ return strlen($this->buffer);
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return true;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a BufferStream');
+ }
+
+ public function eof()
+ {
+ return strlen($this->buffer) === 0;
+ }
+
+ public function tell()
+ {
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
+ }
+
+ /**
+ * Reads data from the buffer.
+ */
+ public function read($length)
+ {
+ $currentLength = strlen($this->buffer);
+
+ if ($length >= $currentLength) {
+ // No need to slice the buffer because we don't have enough data.
+ $result = $this->buffer;
+ $this->buffer = '';
+ } else {
+ // Slice up the result to provide a subset of the buffer.
+ $result = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Writes data to the buffer.
+ */
+ public function write($string)
+ {
+ $this->buffer .= $string;
+
+ // TODO: What should happen here?
+ if (strlen($this->buffer) >= $this->hwm) {
+ return false;
+ }
+
+ return strlen($string);
+ }
+
+ public function getMetadata($key = null)
+ {
+ if ($key == 'hwm') {
+ return $this->hwm;
+ }
+
+ return $key ? null : [];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/CachingStream.php b/vendor/guzzlehttp/psr7/src/CachingStream.php
new file mode 100644
index 0000000..febade9
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/CachingStream.php
@@ -0,0 +1,147 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that can cache previously read bytes from a sequentially
+ * read stream.
+ *
+ * @final
+ */
+class CachingStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var StreamInterface Stream being wrapped */
+ private $remoteStream;
+
+ /** @var int Number of bytes to skip reading due to a write on the buffer */
+ private $skipReadBytes = 0;
+
+ /**
+ * We will treat the buffer object as the body of the stream
+ *
+ * @param StreamInterface $stream Stream to cache. The cursor is assumed to be at the beginning of the stream.
+ * @param StreamInterface $target Optionally specify where data is cached
+ */
+ public function __construct(
+ StreamInterface $stream,
+ StreamInterface $target = null
+ ) {
+ $this->remoteStream = $stream;
+ $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
+ }
+
+ public function getSize()
+ {
+ $remoteSize = $this->remoteStream->getSize();
+
+ if (null === $remoteSize) {
+ return null;
+ }
+
+ return max($this->stream->getSize(), $remoteSize);
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->tell();
+ } elseif ($whence == SEEK_END) {
+ $size = $this->remoteStream->getSize();
+ if ($size === null) {
+ $size = $this->cacheEntireStream();
+ }
+ $byte = $size + $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid whence');
+ }
+
+ $diff = $byte - $this->stream->getSize();
+
+ if ($diff > 0) {
+ // Read the remoteStream until we have read in at least the amount
+ // of bytes requested, or we reach the end of the file.
+ while ($diff > 0 && !$this->remoteStream->eof()) {
+ $this->read($diff);
+ $diff = $byte - $this->stream->getSize();
+ }
+ } else {
+ // We can just do a normal seek since we've already seen this byte.
+ $this->stream->seek($byte);
+ }
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->stream->read($length);
+ $remaining = $length - strlen($data);
+
+ // More data was requested so read from the remote stream
+ if ($remaining) {
+ // If data was written to the buffer in a position that would have
+ // been filled from the remote stream, then we must skip bytes on
+ // the remote stream to emulate overwriting bytes from that
+ // position. This mimics the behavior of other PHP stream wrappers.
+ $remoteData = $this->remoteStream->read(
+ $remaining + $this->skipReadBytes
+ );
+
+ if ($this->skipReadBytes) {
+ $len = strlen($remoteData);
+ $remoteData = substr($remoteData, $this->skipReadBytes);
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
+ }
+
+ $data .= $remoteData;
+ $this->stream->write($remoteData);
+ }
+
+ return $data;
+ }
+
+ public function write($string)
+ {
+ // When appending to the end of the currently read stream, you'll want
+ // to skip bytes from being read from the remote stream to emulate
+ // other stream wrappers. Basically replacing bytes of data of a fixed
+ // length.
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->stream->write($string);
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof() && $this->remoteStream->eof();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ $this->remoteStream->close() && $this->stream->close();
+ }
+
+ private function cacheEntireStream()
+ {
+ $target = new FnStream(['write' => 'strlen']);
+ Utils::copyToStream($this, $target);
+
+ return $this->tell();
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/DroppingStream.php b/vendor/guzzlehttp/psr7/src/DroppingStream.php
new file mode 100644
index 0000000..9f7420c
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/DroppingStream.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that begins dropping data once the size of the underlying
+ * stream becomes too full.
+ *
+ * @final
+ */
+class DroppingStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ private $maxLength;
+
+ /**
+ * @param StreamInterface $stream Underlying stream to decorate.
+ * @param int $maxLength Maximum size before dropping data.
+ */
+ public function __construct(StreamInterface $stream, $maxLength)
+ {
+ $this->stream = $stream;
+ $this->maxLength = $maxLength;
+ }
+
+ public function write($string)
+ {
+ $diff = $this->maxLength - $this->stream->getSize();
+
+ // Begin returning 0 when the underlying stream is too large.
+ if ($diff <= 0) {
+ return 0;
+ }
+
+ // Write the stream or a subset of the stream if needed.
+ if (strlen($string) < $diff) {
+ return $this->stream->write($string);
+ }
+
+ return $this->stream->write(substr($string, 0, $diff));
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/FnStream.php b/vendor/guzzlehttp/psr7/src/FnStream.php
new file mode 100644
index 0000000..76a8cc7
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/FnStream.php
@@ -0,0 +1,163 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Compose stream implementations based on a hash of functions.
+ *
+ * Allows for easy testing and extension of a provided stream without needing
+ * to create a concrete class for a simple extension point.
+ *
+ * @final
+ */
+class FnStream implements StreamInterface
+{
+ /** @var array */
+ private $methods;
+
+ /** @var array Methods that must be implemented in the given array */
+ private static $slots = ['__toString', 'close', 'detach', 'rewind',
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
+ 'isReadable', 'read', 'getContents', 'getMetadata'];
+
+ /**
+ * @param array $methods Hash of method name to a callable.
+ */
+ public function __construct(array $methods)
+ {
+ $this->methods = $methods;
+
+ // Create the functions on the class
+ foreach ($methods as $name => $fn) {
+ $this->{'_fn_' . $name} = $fn;
+ }
+ }
+
+ /**
+ * Lazily determine which methods are not implemented.
+ *
+ * @throws \BadMethodCallException
+ */
+ public function __get($name)
+ {
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
+ . '() is not implemented in the FnStream');
+ }
+
+ /**
+ * The close method is called on the underlying stream only if possible.
+ */
+ public function __destruct()
+ {
+ if (isset($this->_fn_close)) {
+ call_user_func($this->_fn_close);
+ }
+ }
+
+ /**
+ * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
+ *
+ * @throws \LogicException
+ */
+ public function __wakeup()
+ {
+ throw new \LogicException('FnStream should never be unserialized');
+ }
+
+ /**
+ * Adds custom functionality to an underlying stream by intercepting
+ * specific method calls.
+ *
+ * @param StreamInterface $stream Stream to decorate
+ * @param array $methods Hash of method name to a closure
+ *
+ * @return FnStream
+ */
+ public static function decorate(StreamInterface $stream, array $methods)
+ {
+ // If any of the required methods were not provided, then simply
+ // proxy to the decorated stream.
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
+ $methods[$diff] = [$stream, $diff];
+ }
+
+ return new self($methods);
+ }
+
+ public function __toString()
+ {
+ return call_user_func($this->_fn___toString);
+ }
+
+ public function close()
+ {
+ return call_user_func($this->_fn_close);
+ }
+
+ public function detach()
+ {
+ return call_user_func($this->_fn_detach);
+ }
+
+ public function getSize()
+ {
+ return call_user_func($this->_fn_getSize);
+ }
+
+ public function tell()
+ {
+ return call_user_func($this->_fn_tell);
+ }
+
+ public function eof()
+ {
+ return call_user_func($this->_fn_eof);
+ }
+
+ public function isSeekable()
+ {
+ return call_user_func($this->_fn_isSeekable);
+ }
+
+ public function rewind()
+ {
+ call_user_func($this->_fn_rewind);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ call_user_func($this->_fn_seek, $offset, $whence);
+ }
+
+ public function isWritable()
+ {
+ return call_user_func($this->_fn_isWritable);
+ }
+
+ public function write($string)
+ {
+ return call_user_func($this->_fn_write, $string);
+ }
+
+ public function isReadable()
+ {
+ return call_user_func($this->_fn_isReadable);
+ }
+
+ public function read($length)
+ {
+ return call_user_func($this->_fn_read, $length);
+ }
+
+ public function getContents()
+ {
+ return call_user_func($this->_fn_getContents);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return call_user_func($this->_fn_getMetadata, $key);
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Header.php b/vendor/guzzlehttp/psr7/src/Header.php
new file mode 100644
index 0000000..865d742
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Header.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class Header
+{
+ /**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair data
+ * of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ */
+ public static function parse($header)
+ {
+ static $trimmed = "\"' \n\t\r";
+ $params = $matches = [];
+
+ foreach (self::normalize($header) as $val) {
+ $part = [];
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ $m = $matches[0];
+ if (isset($m[1])) {
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
+ } else {
+ $part[] = trim($m[0], $trimmed);
+ }
+ }
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ */
+ public static function normalize($header)
+ {
+ if (!is_array($header)) {
+ return array_map('trim', explode(',', $header));
+ }
+
+ $result = [];
+ foreach ($header as $value) {
+ foreach ((array) $value as $v) {
+ if (strpos($v, ',') === false) {
+ $result[] = $v;
+ continue;
+ }
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
+ $result[] = trim($vv);
+ }
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/InflateStream.php b/vendor/guzzlehttp/psr7/src/InflateStream.php
new file mode 100644
index 0000000..0cbd2cc
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/InflateStream.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
+ *
+ * This stream decorator skips the first 10 bytes of the given stream to remove
+ * the gzip header, converts the provided stream to a PHP stream resource,
+ * then appends the zlib.inflate filter. The stream is then converted back
+ * to a Guzzle stream resource to be used as a Guzzle stream.
+ *
+ * @link http://tools.ietf.org/html/rfc1952
+ * @link http://php.net/manual/en/filters.compression.php
+ *
+ * @final
+ */
+class InflateStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ public function __construct(StreamInterface $stream)
+ {
+ // read the first 10 bytes, ie. gzip header
+ $header = $stream->read(10);
+ $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);
+ // Skip the header, that is 10 + length of filename + 1 (nil) bytes
+ $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
+ $resource = StreamWrapper::getResource($stream);
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
+ $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
+ }
+
+ /**
+ * @param StreamInterface $stream
+ * @param $header
+ *
+ * @return int
+ */
+ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
+ {
+ $filename_header_length = 0;
+
+ if (substr(bin2hex($header), 6, 2) === '08') {
+ // we have a filename, read until nil
+ $filename_header_length = 1;
+ while ($stream->read(1) !== chr(0)) {
+ $filename_header_length++;
+ }
+ }
+
+ return $filename_header_length;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/LazyOpenStream.php b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
new file mode 100644
index 0000000..911e127
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Lazily reads or writes to a file that is opened only after an IO operation
+ * take place on the stream.
+ *
+ * @final
+ */
+class LazyOpenStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var string File to open */
+ private $filename;
+
+ /** @var string */
+ private $mode;
+
+ /**
+ * @param string $filename File to lazily open
+ * @param string $mode fopen mode to use when opening the stream
+ */
+ public function __construct($filename, $mode)
+ {
+ $this->filename = $filename;
+ $this->mode = $mode;
+ }
+
+ /**
+ * Creates the underlying stream lazily when required.
+ *
+ * @return StreamInterface
+ */
+ protected function createStream()
+ {
+ return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/LimitStream.php b/vendor/guzzlehttp/psr7/src/LimitStream.php
new file mode 100644
index 0000000..1173ec4
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/LimitStream.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Decorator used to return only a subset of a stream.
+ *
+ * @final
+ */
+class LimitStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var int Offset to start reading from */
+ private $offset;
+
+ /** @var int Limit the number of bytes that can be read */
+ private $limit;
+
+ /**
+ * @param StreamInterface $stream Stream to wrap
+ * @param int $limit Total number of bytes to allow to be read
+ * from the stream. Pass -1 for no limit.
+ * @param int $offset Position to seek to before reading (only
+ * works on seekable streams).
+ */
+ public function __construct(
+ StreamInterface $stream,
+ $limit = -1,
+ $offset = 0
+ ) {
+ $this->stream = $stream;
+ $this->setLimit($limit);
+ $this->setOffset($offset);
+ }
+
+ public function eof()
+ {
+ // Always return true if the underlying stream is EOF
+ if ($this->stream->eof()) {
+ return true;
+ }
+
+ // No limit and the underlying stream is not at EOF
+ if ($this->limit == -1) {
+ return false;
+ }
+
+ return $this->stream->tell() >= $this->offset + $this->limit;
+ }
+
+ /**
+ * Returns the size of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === ($length = $this->stream->getSize())) {
+ return null;
+ } elseif ($this->limit == -1) {
+ return $length - $this->offset;
+ } else {
+ return min($this->limit, $length - $this->offset);
+ }
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited stream
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence !== SEEK_SET || $offset < 0) {
+ throw new \RuntimeException(sprintf(
+ 'Cannot seek to offset %s with whence %s',
+ $offset,
+ $whence
+ ));
+ }
+
+ $offset += $this->offset;
+
+ if ($this->limit !== -1) {
+ if ($offset > $this->offset + $this->limit) {
+ $offset = $this->offset + $this->limit;
+ }
+ }
+
+ $this->stream->seek($offset);
+ }
+
+ /**
+ * Give a relative tell()
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell() - $this->offset;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @throws \RuntimeException if the stream cannot be seeked.
+ */
+ public function setOffset($offset)
+ {
+ $current = $this->stream->tell();
+
+ if ($current !== $offset) {
+ // If the stream cannot seek to the offset position, then read to it
+ if ($this->stream->isSeekable()) {
+ $this->stream->seek($offset);
+ } elseif ($current > $offset) {
+ throw new \RuntimeException("Could not seek to stream offset $offset");
+ } else {
+ $this->stream->read($offset - $current);
+ }
+ }
+
+ $this->offset = $offset;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the
+ * stream.
+ *
+ * @param int $limit Number of bytes to allow to be read from the stream.
+ * Use -1 for no limit.
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function read($length)
+ {
+ if ($this->limit == -1) {
+ return $this->stream->read($length);
+ }
+
+ // Check if the current position is less than the total allowed
+ // bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte
+ // limit is not exceeded
+ return $this->stream->read(min($remaining, $length));
+ }
+
+ return '';
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Message.php b/vendor/guzzlehttp/psr7/src/Message.php
new file mode 100644
index 0000000..516d1cb
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Message.php
@@ -0,0 +1,252 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+final class Message
+{
+ /**
+ * Returns the string representation of an HTTP message.
+ *
+ * @param MessageInterface $message Message to convert to a string.
+ *
+ * @return string
+ */
+ public static function toString(MessageInterface $message)
+ {
+ if ($message instanceof RequestInterface) {
+ $msg = trim($message->getMethod() . ' '
+ . $message->getRequestTarget())
+ . ' HTTP/' . $message->getProtocolVersion();
+ if (!$message->hasHeader('host')) {
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
+ }
+ } elseif ($message instanceof ResponseInterface) {
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
+ . $message->getStatusCode() . ' '
+ . $message->getReasonPhrase();
+ } else {
+ throw new \InvalidArgumentException('Unknown message type');
+ }
+
+ foreach ($message->getHeaders() as $name => $values) {
+ if (strtolower($name) === 'set-cookie') {
+ foreach ($values as $value) {
+ $msg .= "\r\n{$name}: " . $value;
+ }
+ } else {
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
+ }
+ }
+
+ return "{$msg}\r\n\r\n" . $message->getBody();
+ }
+
+ /**
+ * Get a short summary of the message body.
+ *
+ * Will return `null` if the response is not printable.
+ *
+ * @param MessageInterface $message The message to get the body summary
+ * @param int $truncateAt The maximum allowed size of the summary
+ *
+ * @return string|null
+ */
+ public static function bodySummary(MessageInterface $message, $truncateAt = 120)
+ {
+ $body = $message->getBody();
+
+ if (!$body->isSeekable() || !$body->isReadable()) {
+ return null;
+ }
+
+ $size = $body->getSize();
+
+ if ($size === 0) {
+ return null;
+ }
+
+ $summary = $body->read($truncateAt);
+ $body->rewind();
+
+ if ($size > $truncateAt) {
+ $summary .= ' (truncated...)';
+ }
+
+ // Matches any printable character, including unicode characters:
+ // letters, marks, numbers, punctuation, spacing, and separators.
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary)) {
+ return null;
+ }
+
+ return $summary;
+ }
+
+ /**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()`
+ * returns a value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ */
+ public static function rewindBody(MessageInterface $message)
+ {
+ $body = $message->getBody();
+
+ if ($body->tell()) {
+ $body->rewind();
+ }
+ }
+
+ /**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ */
+ public static function parseMessage($message)
+ {
+ if (!$message) {
+ throw new \InvalidArgumentException('Invalid message');
+ }
+
+ $message = ltrim($message, "\r\n");
+
+ $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
+
+ if ($messageParts === false || count($messageParts) !== 2) {
+ throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
+ }
+
+ list($rawHeaders, $body) = $messageParts;
+ $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
+ $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
+
+ if ($headerParts === false || count($headerParts) !== 2) {
+ throw new \InvalidArgumentException('Invalid message: Missing status line');
+ }
+
+ list($startLine, $rawHeaders) = $headerParts;
+
+ if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
+ // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
+ $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
+ }
+
+ /** @var array[] $headerLines */
+ $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
+
+ // If these aren't the same, then one line didn't match and there's an invalid header.
+ if ($count !== substr_count($rawHeaders, "\n")) {
+ // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
+ if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
+ throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
+ }
+
+ throw new \InvalidArgumentException('Invalid header syntax');
+ }
+
+ $headers = [];
+
+ foreach ($headerLines as $headerLine) {
+ $headers[$headerLine[1]][] = $headerLine[2];
+ }
+
+ return [
+ 'start-line' => $startLine,
+ 'headers' => $headers,
+ 'body' => $body,
+ ];
+ }
+
+ /**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ */
+ public static function parseRequestUri($path, array $headers)
+ {
+ $hostKey = array_filter(array_keys($headers), function ($k) {
+ return strtolower($k) === 'host';
+ });
+
+ // If no host is found, then a full URI cannot be constructed.
+ if (!$hostKey) {
+ return $path;
+ }
+
+ $host = $headers[reset($hostKey)][0];
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
+
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
+ }
+
+ /**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ */
+ public static function parseRequest($message)
+ {
+ $data = self::parseMessage($message);
+ $matches = [];
+ if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
+ throw new \InvalidArgumentException('Invalid request string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+ $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
+
+ $request = new Request(
+ $parts[0],
+ $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],
+ $data['headers'],
+ $data['body'],
+ $version
+ );
+
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
+ }
+
+ /**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ */
+ public static function parseResponse($message)
+ {
+ $data = self::parseMessage($message);
+ // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
+ // between status-code and reason-phrase is required. But browsers accept
+ // responses without space and reason as well.
+ if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
+ throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+
+ return new Response(
+ (int) $parts[1],
+ $data['headers'],
+ $data['body'],
+ explode('/', $parts[0])[1],
+ isset($parts[2]) ? $parts[2] : null
+ );
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php
new file mode 100644
index 0000000..0ac8663
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php
@@ -0,0 +1,270 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Trait implementing functionality common to requests and responses.
+ */
+trait MessageTrait
+{
+ /** @var array Map of all registered headers, as original name => array of values */
+ private $headers = [];
+
+ /** @var array Map of lowercase header name => original name at registration */
+ private $headerNames = [];
+
+ /** @var string */
+ private $protocol = '1.1';
+
+ /** @var StreamInterface|null */
+ private $stream;
+
+ public function getProtocolVersion()
+ {
+ return $this->protocol;
+ }
+
+ public function withProtocolVersion($version)
+ {
+ if ($this->protocol === $version) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->protocol = $version;
+ return $new;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headerNames[strtolower($header)]);
+ }
+
+ public function getHeader($header)
+ {
+ $header = strtolower($header);
+
+ if (!isset($this->headerNames[$header])) {
+ return [];
+ }
+
+ $header = $this->headerNames[$header];
+
+ return $this->headers[$header];
+ }
+
+ public function getHeaderLine($header)
+ {
+ return implode(', ', $this->getHeader($header));
+ }
+
+ public function withHeader($header, $value)
+ {
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+
+ $new = clone $this;
+ if (isset($new->headerNames[$normalized])) {
+ unset($new->headers[$new->headerNames[$normalized]]);
+ }
+ $new->headerNames[$normalized] = $header;
+ $new->headers[$header] = $value;
+
+ return $new;
+ }
+
+ public function withAddedHeader($header, $value)
+ {
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+
+ $new = clone $this;
+ if (isset($new->headerNames[$normalized])) {
+ $header = $this->headerNames[$normalized];
+ $new->headers[$header] = array_merge($this->headers[$header], $value);
+ } else {
+ $new->headerNames[$normalized] = $header;
+ $new->headers[$header] = $value;
+ }
+
+ return $new;
+ }
+
+ public function withoutHeader($header)
+ {
+ $normalized = strtolower($header);
+
+ if (!isset($this->headerNames[$normalized])) {
+ return $this;
+ }
+
+ $header = $this->headerNames[$normalized];
+
+ $new = clone $this;
+ unset($new->headers[$header], $new->headerNames[$normalized]);
+
+ return $new;
+ }
+
+ public function getBody()
+ {
+ if (!$this->stream) {
+ $this->stream = Utils::streamFor('');
+ }
+
+ return $this->stream;
+ }
+
+ public function withBody(StreamInterface $body)
+ {
+ if ($body === $this->stream) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->stream = $body;
+ return $new;
+ }
+
+ private function setHeaders(array $headers)
+ {
+ $this->headerNames = $this->headers = [];
+ foreach ($headers as $header => $value) {
+ if (is_int($header)) {
+ // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec
+ // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.
+ $header = (string) $header;
+ }
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+ if (isset($this->headerNames[$normalized])) {
+ $header = $this->headerNames[$normalized];
+ $this->headers[$header] = array_merge($this->headers[$header], $value);
+ } else {
+ $this->headerNames[$normalized] = $header;
+ $this->headers[$header] = $value;
+ }
+ }
+ }
+
+ /**
+ * @param mixed $value
+ *
+ * @return string[]
+ */
+ private function normalizeHeaderValue($value)
+ {
+ if (!is_array($value)) {
+ return $this->trimAndValidateHeaderValues([$value]);
+ }
+
+ if (count($value) === 0) {
+ throw new \InvalidArgumentException('Header value can not be an empty array.');
+ }
+
+ return $this->trimAndValidateHeaderValues($value);
+ }
+
+ /**
+ * Trims whitespace from the header values.
+ *
+ * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
+ *
+ * header-field = field-name ":" OWS field-value OWS
+ * OWS = *( SP / HTAB )
+ *
+ * @param mixed[] $values Header values
+ *
+ * @return string[] Trimmed header values
+ *
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
+ */
+ private function trimAndValidateHeaderValues(array $values)
+ {
+ return array_map(function ($value) {
+ if (!is_scalar($value) && null !== $value) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header value must be scalar or null but %s provided.',
+ is_object($value) ? get_class($value) : gettype($value)
+ ));
+ }
+
+ $trimmed = trim((string) $value, " \t");
+ $this->assertValue($trimmed);
+
+ return $trimmed;
+ }, array_values($values));
+ }
+
+ /**
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * @param mixed $header
+ *
+ * @return void
+ */
+ private function assertHeader($header)
+ {
+ if (!is_string($header)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header name must be a string but %s provided.',
+ is_object($header) ? get_class($header) : gettype($header)
+ ));
+ }
+
+ if ($header === '') {
+ throw new \InvalidArgumentException('Header name can not be empty.');
+ }
+
+ if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $header)) {
+ throw new \InvalidArgumentException(
+ sprintf(
+ '"%s" is not valid header name',
+ $header
+ )
+ );
+ }
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return void
+ *
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * field-value = *( field-content / obs-fold )
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+ * field-vchar = VCHAR / obs-text
+ * VCHAR = %x21-7E
+ * obs-text = %x80-FF
+ * obs-fold = CRLF 1*( SP / HTAB )
+ */
+ private function assertValue($value)
+ {
+ // The regular expression intentionally does not support the obs-fold production, because as
+ // per RFC 7230#3.2.4:
+ //
+ // A sender MUST NOT generate a message that includes
+ // line folding (i.e., that has any field-value that contains a match to
+ // the obs-fold rule) unless the message is intended for packaging
+ // within the message/http media type.
+ //
+ // Clients must not send a request with line folding and a server sending folded headers is
+ // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
+ // folding is not likely to break any legitimate use case.
+ if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/', $value)) {
+ throw new \InvalidArgumentException(sprintf('"%s" is not valid header value', $value));
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/MimeType.php b/vendor/guzzlehttp/psr7/src/MimeType.php
new file mode 100644
index 0000000..205c7b1
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/MimeType.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class MimeType
+{
+ /**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param string $filename
+ *
+ * @return string|null
+ */
+ public static function fromFilename($filename)
+ {
+ return self::fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
+ }
+
+ /**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param string $extension string The file extension.
+ *
+ * @return string|null
+ *
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ */
+ public static function fromExtension($extension)
+ {
+ static $mimetypes = [
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aac' => 'audio/x-aac',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'atom' => 'application/atom+xml',
+ 'avi' => 'video/x-msvideo',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'cer' => 'application/pkix-cert',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'css' => 'text/css',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'deb' => 'application/x-debian-package',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dvi' => 'application/x-dvi',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'etx' => 'text/x-setext',
+ 'flac' => 'audio/flac',
+ 'flv' => 'video/x-flv',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ini' => 'text/plain',
+ 'iso' => 'application/x-iso9660-image',
+ 'jar' => 'application/java-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'latex' => 'application/x-latex',
+ 'log' => 'text/plain',
+ 'm4a' => 'audio/mp4',
+ 'm4v' => 'video/mp4',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mkv' => 'video/x-matroska',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pdf' => 'application/pdf',
+ 'pgm' => 'image/x-portable-graymap',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'svg' => 'image/svg+xml',
+ 'swf' => 'application/x-shockwave-flash',
+ 'tar' => 'application/x-tar',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'torrent' => 'application/x-bittorrent',
+ 'ttf' => 'application/x-font-ttf',
+ 'txt' => 'text/plain',
+ 'wav' => 'audio/x-wav',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'video/x-ms-wmv',
+ 'woff' => 'application/x-font-woff',
+ 'wsdl' => 'application/wsdl+xml',
+ 'xbm' => 'image/x-xbitmap',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'yaml' => 'text/yaml',
+ 'yml' => 'text/yaml',
+ 'zip' => 'application/zip',
+ ];
+
+ $extension = strtolower($extension);
+
+ return isset($mimetypes[$extension])
+ ? $mimetypes[$extension]
+ : null;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/MultipartStream.php b/vendor/guzzlehttp/psr7/src/MultipartStream.php
new file mode 100644
index 0000000..5a6079a
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/MultipartStream.php
@@ -0,0 +1,158 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream that when read returns bytes for a streaming multipart or
+ * multipart/form-data stream.
+ *
+ * @final
+ */
+class MultipartStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ private $boundary;
+
+ /**
+ * @param array $elements Array of associative arrays, each containing a
+ * required "name" key mapping to the form field,
+ * name, a required "contents" key mapping to a
+ * StreamInterface/resource/string, an optional
+ * "headers" associative array of custom headers,
+ * and an optional "filename" key mapping to a
+ * string to send as the filename in the part.
+ * @param string $boundary You can optionally provide a specific boundary
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(array $elements = [], $boundary = null)
+ {
+ $this->boundary = $boundary ?: sha1(uniqid('', true));
+ $this->stream = $this->createStream($elements);
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the headers needed before transferring the content of a POST file
+ */
+ private function getHeaders(array $headers)
+ {
+ $str = '';
+ foreach ($headers as $key => $value) {
+ $str .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
+ }
+
+ /**
+ * Create the aggregate stream that will be used to upload the POST data
+ */
+ protected function createStream(array $elements)
+ {
+ $stream = new AppendStream();
+
+ foreach ($elements as $element) {
+ $this->addElement($stream, $element);
+ }
+
+ // Add the trailing boundary with CRLF
+ $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));
+
+ return $stream;
+ }
+
+ private function addElement(AppendStream $stream, array $element)
+ {
+ foreach (['contents', 'name'] as $key) {
+ if (!array_key_exists($key, $element)) {
+ throw new \InvalidArgumentException("A '{$key}' key is required");
+ }
+ }
+
+ $element['contents'] = Utils::streamFor($element['contents']);
+
+ if (empty($element['filename'])) {
+ $uri = $element['contents']->getMetadata('uri');
+ if (substr($uri, 0, 6) !== 'php://') {
+ $element['filename'] = $uri;
+ }
+ }
+
+ list($body, $headers) = $this->createElement(
+ $element['name'],
+ $element['contents'],
+ isset($element['filename']) ? $element['filename'] : null,
+ isset($element['headers']) ? $element['headers'] : []
+ );
+
+ $stream->addStream(Utils::streamFor($this->getHeaders($headers)));
+ $stream->addStream($body);
+ $stream->addStream(Utils::streamFor("\r\n"));
+ }
+
+ /**
+ * @return array
+ */
+ private function createElement($name, StreamInterface $stream, $filename, array $headers)
+ {
+ // Set a default content-disposition header if one was no provided
+ $disposition = $this->getHeader($headers, 'content-disposition');
+ if (!$disposition) {
+ $headers['Content-Disposition'] = ($filename === '0' || $filename)
+ ? sprintf(
+ 'form-data; name="%s"; filename="%s"',
+ $name,
+ basename($filename)
+ )
+ : "form-data; name=\"{$name}\"";
+ }
+
+ // Set a default content-length header if one was no provided
+ $length = $this->getHeader($headers, 'content-length');
+ if (!$length) {
+ if ($length = $stream->getSize()) {
+ $headers['Content-Length'] = (string) $length;
+ }
+ }
+
+ // Set a default Content-Type if one was not supplied
+ $type = $this->getHeader($headers, 'content-type');
+ if (!$type && ($filename === '0' || $filename)) {
+ if ($type = MimeType::fromFilename($filename)) {
+ $headers['Content-Type'] = $type;
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ private function getHeader(array $headers, $key)
+ {
+ $lowercaseHeader = strtolower($key);
+ foreach ($headers as $k => $v) {
+ if (strtolower($k) === $lowercaseHeader) {
+ return $v;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/NoSeekStream.php b/vendor/guzzlehttp/psr7/src/NoSeekStream.php
new file mode 100644
index 0000000..d66bdde
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/NoSeekStream.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that prevents a stream from being seeked.
+ *
+ * @final
+ */
+class NoSeekStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a NoSeekStream');
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/PumpStream.php b/vendor/guzzlehttp/psr7/src/PumpStream.php
new file mode 100644
index 0000000..44c7b58
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/PumpStream.php
@@ -0,0 +1,170 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a read only stream that pumps data from a PHP callable.
+ *
+ * When invoking the provided callable, the PumpStream will pass the amount of
+ * data requested to read to the callable. The callable can choose to ignore
+ * this value and return fewer or more bytes than requested. Any extra data
+ * returned by the provided callable is buffered internally until drained using
+ * the read() function of the PumpStream. The provided callable MUST return
+ * false when there is no more data to read.
+ *
+ * @final
+ */
+class PumpStream implements StreamInterface
+{
+ /** @var callable */
+ private $source;
+
+ /** @var int */
+ private $size;
+
+ /** @var int */
+ private $tellPos = 0;
+
+ /** @var array */
+ private $metadata;
+
+ /** @var BufferStream */
+ private $buffer;
+
+ /**
+ * @param callable $source Source of the stream data. The callable MAY
+ * accept an integer argument used to control the
+ * amount of data to return. The callable MUST
+ * return a string when called, or false on error
+ * or EOF.
+ * @param array $options Stream options:
+ * - metadata: Hash of metadata to use with stream.
+ * - size: Size of the stream, if known.
+ */
+ public function __construct(callable $source, array $options = [])
+ {
+ $this->source = $source;
+ $this->size = isset($options['size']) ? $options['size'] : null;
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
+ $this->buffer = new BufferStream();
+ }
+
+ public function __toString()
+ {
+ try {
+ return Utils::copyToString($this);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->tellPos = false;
+ $this->source = null;
+
+ return null;
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ return $this->tellPos;
+ }
+
+ public function eof()
+ {
+ return !$this->source;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a PumpStream');
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to a PumpStream');
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function read($length)
+ {
+ $data = $this->buffer->read($length);
+ $readLen = strlen($data);
+ $this->tellPos += $readLen;
+ $remaining = $length - $readLen;
+
+ if ($remaining) {
+ $this->pump($remaining);
+ $data .= $this->buffer->read($remaining);
+ $this->tellPos += strlen($data) - $readLen;
+ }
+
+ return $data;
+ }
+
+ public function getContents()
+ {
+ $result = '';
+ while (!$this->eof()) {
+ $result .= $this->read(1000000);
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!$key) {
+ return $this->metadata;
+ }
+
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
+ }
+
+ private function pump($length)
+ {
+ if ($this->source) {
+ do {
+ $data = call_user_func($this->source, $length);
+ if ($data === false || $data === null) {
+ $this->source = null;
+ return;
+ }
+ $this->buffer->write($data);
+ $length -= strlen($data);
+ } while ($length > 0);
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Query.php b/vendor/guzzlehttp/psr7/src/Query.php
new file mode 100644
index 0000000..5a7cc03
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Query.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class Query
+{
+ /**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key
+ * value pair will become an array. This function does not parse nested
+ * PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`
+ * will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
+ *
+ * @param string $str Query string to parse
+ * @param int|bool $urlEncoding How the query string is encoded
+ *
+ * @return array
+ */
+ public static function parse($str, $urlEncoding = true)
+ {
+ $result = [];
+
+ if ($str === '') {
+ return $result;
+ }
+
+ if ($urlEncoding === true) {
+ $decoder = function ($value) {
+ return rawurldecode(str_replace('+', ' ', $value));
+ };
+ } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
+ $decoder = 'rawurldecode';
+ } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
+ $decoder = 'urldecode';
+ } else {
+ $decoder = function ($str) {
+ return $str;
+ };
+ }
+
+ foreach (explode('&', $str) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ $key = $decoder($parts[0]);
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
+ if (!isset($result[$key])) {
+ $result[$key] = $value;
+ } else {
+ if (!is_array($result[$key])) {
+ $result[$key] = [$result[$key]];
+ }
+ $result[$key][] = $value;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of `parse()` to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like `http_build_query()` would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ *
+ * @return string
+ */
+ public static function build(array $params, $encoding = PHP_QUERY_RFC3986)
+ {
+ if (!$params) {
+ return '';
+ }
+
+ if ($encoding === false) {
+ $encoder = function ($str) {
+ return $str;
+ };
+ } elseif ($encoding === PHP_QUERY_RFC3986) {
+ $encoder = 'rawurlencode';
+ } elseif ($encoding === PHP_QUERY_RFC1738) {
+ $encoder = 'urlencode';
+ } else {
+ throw new \InvalidArgumentException('Invalid type');
+ }
+
+ $qs = '';
+ foreach ($params as $k => $v) {
+ $k = $encoder($k);
+ if (!is_array($v)) {
+ $qs .= $k;
+ if ($v !== null) {
+ $qs .= '=' . $encoder($v);
+ }
+ $qs .= '&';
+ } else {
+ foreach ($v as $vv) {
+ $qs .= $k;
+ if ($vv !== null) {
+ $qs .= '=' . $encoder($vv);
+ }
+ $qs .= '&';
+ }
+ }
+ }
+
+ return $qs ? (string) substr($qs, 0, -1) : '';
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Request.php b/vendor/guzzlehttp/psr7/src/Request.php
new file mode 100644
index 0000000..c1cdaeb
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Request.php
@@ -0,0 +1,152 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * PSR-7 request implementation.
+ */
+class Request implements RequestInterface
+{
+ use MessageTrait;
+
+ /** @var string */
+ private $method;
+
+ /** @var string|null */
+ private $requestTarget;
+
+ /** @var UriInterface */
+ private $uri;
+
+ /**
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI
+ * @param array $headers Request headers
+ * @param string|resource|StreamInterface|null $body Request body
+ * @param string $version Protocol version
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $version = '1.1'
+ ) {
+ $this->assertMethod($method);
+ if (!($uri instanceof UriInterface)) {
+ $uri = new Uri($uri);
+ }
+
+ $this->method = strtoupper($method);
+ $this->uri = $uri;
+ $this->setHeaders($headers);
+ $this->protocol = $version;
+
+ if (!isset($this->headerNames['host'])) {
+ $this->updateHostFromUri();
+ }
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = Utils::streamFor($body);
+ }
+ }
+
+ public function getRequestTarget()
+ {
+ if ($this->requestTarget !== null) {
+ return $this->requestTarget;
+ }
+
+ $target = $this->uri->getPath();
+ if ($target == '') {
+ $target = '/';
+ }
+ if ($this->uri->getQuery() != '') {
+ $target .= '?' . $this->uri->getQuery();
+ }
+
+ return $target;
+ }
+
+ public function withRequestTarget($requestTarget)
+ {
+ if (preg_match('#\s#', $requestTarget)) {
+ throw new InvalidArgumentException(
+ 'Invalid request target provided; cannot contain whitespace'
+ );
+ }
+
+ $new = clone $this;
+ $new->requestTarget = $requestTarget;
+ return $new;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function withMethod($method)
+ {
+ $this->assertMethod($method);
+ $new = clone $this;
+ $new->method = strtoupper($method);
+ return $new;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ if ($uri === $this->uri) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->uri = $uri;
+
+ if (!$preserveHost || !isset($this->headerNames['host'])) {
+ $new->updateHostFromUri();
+ }
+
+ return $new;
+ }
+
+ private function updateHostFromUri()
+ {
+ $host = $this->uri->getHost();
+
+ if ($host == '') {
+ return;
+ }
+
+ if (($port = $this->uri->getPort()) !== null) {
+ $host .= ':' . $port;
+ }
+
+ if (isset($this->headerNames['host'])) {
+ $header = $this->headerNames['host'];
+ } else {
+ $header = 'Host';
+ $this->headerNames['host'] = 'Host';
+ }
+ // Ensure Host is the first header.
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
+ $this->headers = [$header => [$host]] + $this->headers;
+ }
+
+ private function assertMethod($method)
+ {
+ if (!is_string($method) || $method === '') {
+ throw new \InvalidArgumentException('Method must be a non-empty string.');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Response.php b/vendor/guzzlehttp/psr7/src/Response.php
new file mode 100644
index 0000000..8c01a0f
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Response.php
@@ -0,0 +1,155 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * PSR-7 response implementation.
+ */
+class Response implements ResponseInterface
+{
+ use MessageTrait;
+
+ /** @var array Map of standard HTTP status code/reason phrases */
+ private static $phrases = [
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-status',
+ 208 => 'Already Reported',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Time-out',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested range not satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Unordered Collection',
+ 426 => 'Upgrade Required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 451 => 'Unavailable For Legal Reasons',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Time-out',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 511 => 'Network Authentication Required',
+ ];
+
+ /** @var string */
+ private $reasonPhrase = '';
+
+ /** @var int */
+ private $statusCode = 200;
+
+ /**
+ * @param int $status Status code
+ * @param array $headers Response headers
+ * @param string|resource|StreamInterface|null $body Response body
+ * @param string $version Protocol version
+ * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
+ */
+ public function __construct(
+ $status = 200,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ $reason = null
+ ) {
+ $this->assertStatusCodeIsInteger($status);
+ $status = (int) $status;
+ $this->assertStatusCodeRange($status);
+
+ $this->statusCode = $status;
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = Utils::streamFor($body);
+ }
+
+ $this->setHeaders($headers);
+ if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
+ $this->reasonPhrase = self::$phrases[$this->statusCode];
+ } else {
+ $this->reasonPhrase = (string) $reason;
+ }
+
+ $this->protocol = $version;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $this->assertStatusCodeIsInteger($code);
+ $code = (int) $code;
+ $this->assertStatusCodeRange($code);
+
+ $new = clone $this;
+ $new->statusCode = $code;
+ if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
+ $reasonPhrase = self::$phrases[$new->statusCode];
+ }
+ $new->reasonPhrase = (string) $reasonPhrase;
+ return $new;
+ }
+
+ private function assertStatusCodeIsInteger($statusCode)
+ {
+ if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
+ throw new \InvalidArgumentException('Status code must be an integer value.');
+ }
+ }
+
+ private function assertStatusCodeRange($statusCode)
+ {
+ if ($statusCode < 100 || $statusCode >= 600) {
+ throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Rfc7230.php b/vendor/guzzlehttp/psr7/src/Rfc7230.php
new file mode 100644
index 0000000..51b571f
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Rfc7230.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class Rfc7230
+{
+ /**
+ * Header related regular expressions (copied from amphp/http package)
+ * (Note: once we require PHP 7.x we could just depend on the upstream package)
+ *
+ * Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
+ *
+ * @link https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
+ *
+ * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
+ */
+ const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
+ const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
+}
diff --git a/vendor/guzzlehttp/psr7/src/ServerRequest.php b/vendor/guzzlehttp/psr7/src/ServerRequest.php
new file mode 100644
index 0000000..e6d26f5
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/ServerRequest.php
@@ -0,0 +1,379 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Server-side HTTP request
+ *
+ * Extends the Request definition to add methods for accessing incoming data,
+ * specifically server parameters, cookies, matched path parameters, query
+ * string arguments, body parameters, and upload file information.
+ *
+ * "Attributes" are discovered via decomposing the request (and usually
+ * specifically the URI path), and typically will be injected by the application.
+ *
+ * Requests are considered immutable; all methods that might change state are
+ * implemented such that they retain the internal state of the current
+ * message and return a new instance that contains the changed state.
+ */
+class ServerRequest extends Request implements ServerRequestInterface
+{
+ /**
+ * @var array
+ */
+ private $attributes = [];
+
+ /**
+ * @var array
+ */
+ private $cookieParams = [];
+
+ /**
+ * @var array|object|null
+ */
+ private $parsedBody;
+
+ /**
+ * @var array
+ */
+ private $queryParams = [];
+
+ /**
+ * @var array
+ */
+ private $serverParams;
+
+ /**
+ * @var array
+ */
+ private $uploadedFiles = [];
+
+ /**
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI
+ * @param array $headers Request headers
+ * @param string|resource|StreamInterface|null $body Request body
+ * @param string $version Protocol version
+ * @param array $serverParams Typically the $_SERVER superglobal
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ array $serverParams = []
+ ) {
+ $this->serverParams = $serverParams;
+
+ parent::__construct($method, $uri, $headers, $body, $version);
+ }
+
+ /**
+ * Return an UploadedFile instance array.
+ *
+ * @param array $files A array which respect $_FILES structure
+ *
+ * @return array
+ *
+ * @throws InvalidArgumentException for unrecognized values
+ */
+ public static function normalizeFiles(array $files)
+ {
+ $normalized = [];
+
+ foreach ($files as $key => $value) {
+ if ($value instanceof UploadedFileInterface) {
+ $normalized[$key] = $value;
+ } elseif (is_array($value) && isset($value['tmp_name'])) {
+ $normalized[$key] = self::createUploadedFileFromSpec($value);
+ } elseif (is_array($value)) {
+ $normalized[$key] = self::normalizeFiles($value);
+ continue;
+ } else {
+ throw new InvalidArgumentException('Invalid value in files specification');
+ }
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * Create and return an UploadedFile instance from a $_FILES specification.
+ *
+ * If the specification represents an array of values, this method will
+ * delegate to normalizeNestedFileSpec() and return that return value.
+ *
+ * @param array $value $_FILES struct
+ *
+ * @return array|UploadedFileInterface
+ */
+ private static function createUploadedFileFromSpec(array $value)
+ {
+ if (is_array($value['tmp_name'])) {
+ return self::normalizeNestedFileSpec($value);
+ }
+
+ return new UploadedFile(
+ $value['tmp_name'],
+ (int) $value['size'],
+ (int) $value['error'],
+ $value['name'],
+ $value['type']
+ );
+ }
+
+ /**
+ * Normalize an array of file specifications.
+ *
+ * Loops through all nested files and returns a normalized array of
+ * UploadedFileInterface instances.
+ *
+ * @param array $files
+ *
+ * @return UploadedFileInterface[]
+ */
+ private static function normalizeNestedFileSpec(array $files = [])
+ {
+ $normalizedFiles = [];
+
+ foreach (array_keys($files['tmp_name']) as $key) {
+ $spec = [
+ 'tmp_name' => $files['tmp_name'][$key],
+ 'size' => $files['size'][$key],
+ 'error' => $files['error'][$key],
+ 'name' => $files['name'][$key],
+ 'type' => $files['type'][$key],
+ ];
+ $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
+ }
+
+ return $normalizedFiles;
+ }
+
+ /**
+ * Return a ServerRequest populated with superglobals:
+ * $_GET
+ * $_POST
+ * $_COOKIE
+ * $_FILES
+ * $_SERVER
+ *
+ * @return ServerRequestInterface
+ */
+ public static function fromGlobals()
+ {
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
+ $headers = getallheaders();
+ $uri = self::getUriFromGlobals();
+ $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
+
+ $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
+
+ return $serverRequest
+ ->withCookieParams($_COOKIE)
+ ->withQueryParams($_GET)
+ ->withParsedBody($_POST)
+ ->withUploadedFiles(self::normalizeFiles($_FILES));
+ }
+
+ private static function extractHostAndPortFromAuthority($authority)
+ {
+ $uri = 'http://' . $authority;
+ $parts = parse_url($uri);
+ if (false === $parts) {
+ return [null, null];
+ }
+
+ $host = isset($parts['host']) ? $parts['host'] : null;
+ $port = isset($parts['port']) ? $parts['port'] : null;
+
+ return [$host, $port];
+ }
+
+ /**
+ * Get a Uri populated with values from $_SERVER.
+ *
+ * @return UriInterface
+ */
+ public static function getUriFromGlobals()
+ {
+ $uri = new Uri('');
+
+ $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
+
+ $hasPort = false;
+ if (isset($_SERVER['HTTP_HOST'])) {
+ list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
+ if ($host !== null) {
+ $uri = $uri->withHost($host);
+ }
+
+ if ($port !== null) {
+ $hasPort = true;
+ $uri = $uri->withPort($port);
+ }
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_NAME']);
+ } elseif (isset($_SERVER['SERVER_ADDR'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
+ }
+
+ if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
+ $uri = $uri->withPort($_SERVER['SERVER_PORT']);
+ }
+
+ $hasQuery = false;
+ if (isset($_SERVER['REQUEST_URI'])) {
+ $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
+ $uri = $uri->withPath($requestUriParts[0]);
+ if (isset($requestUriParts[1])) {
+ $hasQuery = true;
+ $uri = $uri->withQuery($requestUriParts[1]);
+ }
+ }
+
+ if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
+ $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
+ }
+
+ return $uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getServerParams()
+ {
+ return $this->serverParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUploadedFiles()
+ {
+ return $this->uploadedFiles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withUploadedFiles(array $uploadedFiles)
+ {
+ $new = clone $this;
+ $new->uploadedFiles = $uploadedFiles;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCookieParams()
+ {
+ return $this->cookieParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withCookieParams(array $cookies)
+ {
+ $new = clone $this;
+ $new->cookieParams = $cookies;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getQueryParams()
+ {
+ return $this->queryParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withQueryParams(array $query)
+ {
+ $new = clone $this;
+ $new->queryParams = $query;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParsedBody()
+ {
+ return $this->parsedBody;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withParsedBody($data)
+ {
+ $new = clone $this;
+ $new->parsedBody = $data;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttribute($attribute, $default = null)
+ {
+ if (false === array_key_exists($attribute, $this->attributes)) {
+ return $default;
+ }
+
+ return $this->attributes[$attribute];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withAttribute($attribute, $value)
+ {
+ $new = clone $this;
+ $new->attributes[$attribute] = $value;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withoutAttribute($attribute)
+ {
+ if (false === array_key_exists($attribute, $this->attributes)) {
+ return $this;
+ }
+
+ $new = clone $this;
+ unset($new->attributes[$attribute]);
+
+ return $new;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Stream.php b/vendor/guzzlehttp/psr7/src/Stream.php
new file mode 100644
index 0000000..3865d6d
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Stream.php
@@ -0,0 +1,270 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * PHP stream implementation.
+ *
+ * @var $stream
+ */
+class Stream implements StreamInterface
+{
+ /**
+ * Resource modes.
+ *
+ * @var string
+ *
+ * @see http://php.net/manual/function.fopen.php
+ * @see http://php.net/manual/en/function.gzopen.php
+ */
+ const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/';
+ const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';
+
+ private $stream;
+ private $size;
+ private $seekable;
+ private $readable;
+ private $writable;
+ private $uri;
+ private $customMetadata;
+
+ /**
+ * This constructor accepts an associative array of options.
+ *
+ * - size: (int) If a read stream would otherwise have an indeterminate
+ * size, but the size is known due to foreknowledge, then you can
+ * provide that size, in bytes.
+ * - metadata: (array) Any additional metadata to return when the metadata
+ * of the stream is accessed.
+ *
+ * @param resource $stream Stream resource to wrap.
+ * @param array $options Associative array of options.
+ *
+ * @throws \InvalidArgumentException if the stream is not a stream resource
+ */
+ public function __construct($stream, $options = [])
+ {
+ if (!is_resource($stream)) {
+ throw new \InvalidArgumentException('Stream must be a resource');
+ }
+
+ if (isset($options['size'])) {
+ $this->size = $options['size'];
+ }
+
+ $this->customMetadata = isset($options['metadata'])
+ ? $options['metadata']
+ : [];
+
+ $this->stream = $stream;
+ $meta = stream_get_meta_data($this->stream);
+ $this->seekable = $meta['seekable'];
+ $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']);
+ $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']);
+ $this->uri = $this->getMetadata('uri');
+ }
+
+ /**
+ * Closes the stream when the destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ $contents = stream_get_contents($this->stream);
+
+ if ($contents === false) {
+ throw new \RuntimeException('Unable to read stream contents');
+ }
+
+ return $contents;
+ }
+
+ public function close()
+ {
+ if (isset($this->stream)) {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->detach();
+ }
+ }
+
+ public function detach()
+ {
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ $result = $this->stream;
+ unset($this->stream);
+ $this->size = $this->uri = null;
+ $this->readable = $this->writable = $this->seekable = false;
+
+ return $result;
+ }
+
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ // Clear the stat cache if the stream has a URI
+ if ($this->uri) {
+ clearstatcache(true, $this->uri);
+ }
+
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ }
+
+ return null;
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function eof()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ return feof($this->stream);
+ }
+
+ public function tell()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ $result = ftell($this->stream);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to determine stream position');
+ }
+
+ return $result;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $whence = (int) $whence;
+
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->seekable) {
+ throw new \RuntimeException('Stream is not seekable');
+ }
+ if (fseek($this->stream, $offset, $whence) === -1) {
+ throw new \RuntimeException('Unable to seek to stream position '
+ . $offset . ' with whence ' . var_export($whence, true));
+ }
+ }
+
+ public function read($length)
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->readable) {
+ throw new \RuntimeException('Cannot read from non-readable stream');
+ }
+ if ($length < 0) {
+ throw new \RuntimeException('Length parameter cannot be negative');
+ }
+
+ if (0 === $length) {
+ return '';
+ }
+
+ $string = fread($this->stream, $length);
+ if (false === $string) {
+ throw new \RuntimeException('Unable to read from stream');
+ }
+
+ return $string;
+ }
+
+ public function write($string)
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->writable) {
+ throw new \RuntimeException('Cannot write to a non-writable stream');
+ }
+
+ // We can't know the size after writing anything
+ $this->size = null;
+ $result = fwrite($this->stream, $string);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to write to stream');
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!isset($this->stream)) {
+ return $key ? null : [];
+ } elseif (!$key) {
+ return $this->customMetadata + stream_get_meta_data($this->stream);
+ } elseif (isset($this->customMetadata[$key])) {
+ return $this->customMetadata[$key];
+ }
+
+ $meta = stream_get_meta_data($this->stream);
+
+ return isset($meta[$key]) ? $meta[$key] : null;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
new file mode 100644
index 0000000..5025dd6
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
@@ -0,0 +1,152 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator trait
+ *
+ * @property StreamInterface stream
+ */
+trait StreamDecoratorTrait
+{
+ /**
+ * @param StreamInterface $stream Stream to decorate
+ */
+ public function __construct(StreamInterface $stream)
+ {
+ $this->stream = $stream;
+ }
+
+ /**
+ * Magic method used to create a new stream if streams are not added in
+ * the constructor of a decorator (e.g., LazyOpenStream).
+ *
+ * @param string $name Name of the property (allows "stream" only).
+ *
+ * @return StreamInterface
+ */
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ $this->stream = $this->createStream();
+ return $this->stream;
+ }
+
+ throw new \UnexpectedValueException("$name not found on class");
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
+ trigger_error('StreamDecorator::__toString exception: '
+ . (string) $e, E_USER_ERROR);
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ return Utils::copyToString($this);
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ $result = call_user_func_array([$this->stream, $method], $args);
+
+ // Always return the wrapped object if the result is a return $this
+ return $result === $this->stream ? $this : $result;
+ }
+
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+ /**
+ * Implement in subclasses to dynamically create streams when requested.
+ *
+ * @return StreamInterface
+ *
+ * @throws \BadMethodCallException
+ */
+ protected function createStream()
+ {
+ throw new \BadMethodCallException('Not implemented');
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/StreamWrapper.php b/vendor/guzzlehttp/psr7/src/StreamWrapper.php
new file mode 100644
index 0000000..fc7cb96
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/StreamWrapper.php
@@ -0,0 +1,165 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Converts Guzzle streams into PHP stream resources.
+ *
+ * @final
+ */
+class StreamWrapper
+{
+ /** @var resource */
+ public $context;
+
+ /** @var StreamInterface */
+ private $stream;
+
+ /** @var string r, r+, or w */
+ private $mode;
+
+ /**
+ * Returns a resource representing the stream.
+ *
+ * @param StreamInterface $stream The stream to get a resource for
+ *
+ * @return resource
+ *
+ * @throws \InvalidArgumentException if stream is not readable or writable
+ */
+ public static function getResource(StreamInterface $stream)
+ {
+ self::register();
+
+ if ($stream->isReadable()) {
+ $mode = $stream->isWritable() ? 'r+' : 'r';
+ } elseif ($stream->isWritable()) {
+ $mode = 'w';
+ } else {
+ throw new \InvalidArgumentException('The stream must be readable, '
+ . 'writable, or both.');
+ }
+
+ return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
+ }
+
+ /**
+ * Creates a stream context that can be used to open a stream as a php stream resource.
+ *
+ * @param StreamInterface $stream
+ *
+ * @return resource
+ */
+ public static function createStreamContext(StreamInterface $stream)
+ {
+ return stream_context_create([
+ 'guzzle' => ['stream' => $stream]
+ ]);
+ }
+
+ /**
+ * Registers the stream wrapper if needed
+ */
+ public static function register()
+ {
+ if (!in_array('guzzle', stream_get_wrappers())) {
+ stream_wrapper_register('guzzle', __CLASS__);
+ }
+ }
+
+ public function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $options = stream_context_get_options($this->context);
+
+ if (!isset($options['guzzle']['stream'])) {
+ return false;
+ }
+
+ $this->mode = $mode;
+ $this->stream = $options['guzzle']['stream'];
+
+ return true;
+ }
+
+ public function stream_read($count)
+ {
+ return $this->stream->read($count);
+ }
+
+ public function stream_write($data)
+ {
+ return (int) $this->stream->write($data);
+ }
+
+ public function stream_tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function stream_eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ $this->stream->seek($offset, $whence);
+
+ return true;
+ }
+
+ public function stream_cast($cast_as)
+ {
+ $stream = clone($this->stream);
+
+ return $stream->detach();
+ }
+
+ public function stream_stat()
+ {
+ static $modeMap = [
+ 'r' => 33060,
+ 'rb' => 33060,
+ 'r+' => 33206,
+ 'w' => 33188,
+ 'wb' => 33188
+ ];
+
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => $modeMap[$this->mode],
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => $this->stream->getSize() ?: 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+
+ public function url_stat($path, $flags)
+ {
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => 0,
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UploadedFile.php b/vendor/guzzlehttp/psr7/src/UploadedFile.php
new file mode 100644
index 0000000..bf342c4
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/UploadedFile.php
@@ -0,0 +1,328 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use RuntimeException;
+
+class UploadedFile implements UploadedFileInterface
+{
+ /**
+ * @var int[]
+ */
+ private static $errors = [
+ UPLOAD_ERR_OK,
+ UPLOAD_ERR_INI_SIZE,
+ UPLOAD_ERR_FORM_SIZE,
+ UPLOAD_ERR_PARTIAL,
+ UPLOAD_ERR_NO_FILE,
+ UPLOAD_ERR_NO_TMP_DIR,
+ UPLOAD_ERR_CANT_WRITE,
+ UPLOAD_ERR_EXTENSION,
+ ];
+
+ /**
+ * @var string
+ */
+ private $clientFilename;
+
+ /**
+ * @var string
+ */
+ private $clientMediaType;
+
+ /**
+ * @var int
+ */
+ private $error;
+
+ /**
+ * @var string|null
+ */
+ private $file;
+
+ /**
+ * @var bool
+ */
+ private $moved = false;
+
+ /**
+ * @var int
+ */
+ private $size;
+
+ /**
+ * @var StreamInterface|null
+ */
+ private $stream;
+
+ /**
+ * @param StreamInterface|string|resource $streamOrFile
+ * @param int $size
+ * @param int $errorStatus
+ * @param string|null $clientFilename
+ * @param string|null $clientMediaType
+ */
+ public function __construct(
+ $streamOrFile,
+ $size,
+ $errorStatus,
+ $clientFilename = null,
+ $clientMediaType = null
+ ) {
+ $this->setError($errorStatus);
+ $this->setSize($size);
+ $this->setClientFilename($clientFilename);
+ $this->setClientMediaType($clientMediaType);
+
+ if ($this->isOk()) {
+ $this->setStreamOrFile($streamOrFile);
+ }
+ }
+
+ /**
+ * Depending on the value set file or stream variable
+ *
+ * @param mixed $streamOrFile
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setStreamOrFile($streamOrFile)
+ {
+ if (is_string($streamOrFile)) {
+ $this->file = $streamOrFile;
+ } elseif (is_resource($streamOrFile)) {
+ $this->stream = new Stream($streamOrFile);
+ } elseif ($streamOrFile instanceof StreamInterface) {
+ $this->stream = $streamOrFile;
+ } else {
+ throw new InvalidArgumentException(
+ 'Invalid stream or file provided for UploadedFile'
+ );
+ }
+ }
+
+ /**
+ * @param int $error
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setError($error)
+ {
+ if (false === is_int($error)) {
+ throw new InvalidArgumentException(
+ 'Upload file error status must be an integer'
+ );
+ }
+
+ if (false === in_array($error, UploadedFile::$errors)) {
+ throw new InvalidArgumentException(
+ 'Invalid error status for UploadedFile'
+ );
+ }
+
+ $this->error = $error;
+ }
+
+ /**
+ * @param int $size
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setSize($size)
+ {
+ if (false === is_int($size)) {
+ throw new InvalidArgumentException(
+ 'Upload file size must be an integer'
+ );
+ }
+
+ $this->size = $size;
+ }
+
+ /**
+ * @param mixed $param
+ *
+ * @return bool
+ */
+ private function isStringOrNull($param)
+ {
+ return in_array(gettype($param), ['string', 'NULL']);
+ }
+
+ /**
+ * @param mixed $param
+ *
+ * @return bool
+ */
+ private function isStringNotEmpty($param)
+ {
+ return is_string($param) && false === empty($param);
+ }
+
+ /**
+ * @param string|null $clientFilename
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setClientFilename($clientFilename)
+ {
+ if (false === $this->isStringOrNull($clientFilename)) {
+ throw new InvalidArgumentException(
+ 'Upload file client filename must be a string or null'
+ );
+ }
+
+ $this->clientFilename = $clientFilename;
+ }
+
+ /**
+ * @param string|null $clientMediaType
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setClientMediaType($clientMediaType)
+ {
+ if (false === $this->isStringOrNull($clientMediaType)) {
+ throw new InvalidArgumentException(
+ 'Upload file client media type must be a string or null'
+ );
+ }
+
+ $this->clientMediaType = $clientMediaType;
+ }
+
+ /**
+ * Return true if there is no upload error
+ *
+ * @return bool
+ */
+ private function isOk()
+ {
+ return $this->error === UPLOAD_ERR_OK;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isMoved()
+ {
+ return $this->moved;
+ }
+
+ /**
+ * @throws RuntimeException if is moved or not ok
+ */
+ private function validateActive()
+ {
+ if (false === $this->isOk()) {
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
+ }
+
+ if ($this->isMoved()) {
+ throw new RuntimeException('Cannot retrieve stream after it has already been moved');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws RuntimeException if the upload was not successful.
+ */
+ public function getStream()
+ {
+ $this->validateActive();
+
+ if ($this->stream instanceof StreamInterface) {
+ return $this->stream;
+ }
+
+ return new LazyOpenStream($this->file, 'r+');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @see http://php.net/is_uploaded_file
+ * @see http://php.net/move_uploaded_file
+ *
+ * @param string $targetPath Path to which to move the uploaded file.
+ *
+ * @throws RuntimeException if the upload was not successful.
+ * @throws InvalidArgumentException if the $path specified is invalid.
+ * @throws RuntimeException on any error during the move operation, or on
+ * the second or subsequent call to the method.
+ */
+ public function moveTo($targetPath)
+ {
+ $this->validateActive();
+
+ if (false === $this->isStringNotEmpty($targetPath)) {
+ throw new InvalidArgumentException(
+ 'Invalid path provided for move operation; must be a non-empty string'
+ );
+ }
+
+ if ($this->file) {
+ $this->moved = php_sapi_name() == 'cli'
+ ? rename($this->file, $targetPath)
+ : move_uploaded_file($this->file, $targetPath);
+ } else {
+ Utils::copyToStream(
+ $this->getStream(),
+ new LazyOpenStream($targetPath, 'w')
+ );
+
+ $this->moved = true;
+ }
+
+ if (false === $this->moved) {
+ throw new RuntimeException(
+ sprintf('Uploaded file could not be moved to %s', $targetPath)
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return int|null The file size in bytes or null if unknown.
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @see http://php.net/manual/en/features.file-upload.errors.php
+ *
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return string|null The filename sent by the client or null if none
+ * was provided.
+ */
+ public function getClientFilename()
+ {
+ return $this->clientFilename;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientMediaType()
+ {
+ return $this->clientMediaType;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Uri.php b/vendor/guzzlehttp/psr7/src/Uri.php
new file mode 100644
index 0000000..0f9f020
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Uri.php
@@ -0,0 +1,810 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * PSR-7 URI implementation.
+ *
+ * @author Michael Dowling
+ * @author Tobias Schultze
+ * @author Matthew Weier O'Phinney
+ */
+class Uri implements UriInterface
+{
+ /**
+ * Absolute http and https URIs require a host per RFC 7230 Section 2.7
+ * but in generic URIs the host can be empty. So for http(s) URIs
+ * we apply this default host when no host is given yet to form a
+ * valid URI.
+ */
+ const HTTP_DEFAULT_HOST = 'localhost';
+
+ private static $defaultPorts = [
+ 'http' => 80,
+ 'https' => 443,
+ 'ftp' => 21,
+ 'gopher' => 70,
+ 'nntp' => 119,
+ 'news' => 119,
+ 'telnet' => 23,
+ 'tn3270' => 23,
+ 'imap' => 143,
+ 'pop' => 110,
+ 'ldap' => 389,
+ ];
+
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
+
+ /** @var string Uri scheme. */
+ private $scheme = '';
+
+ /** @var string Uri user info. */
+ private $userInfo = '';
+
+ /** @var string Uri host. */
+ private $host = '';
+
+ /** @var int|null Uri port. */
+ private $port;
+
+ /** @var string Uri path. */
+ private $path = '';
+
+ /** @var string Uri query string. */
+ private $query = '';
+
+ /** @var string Uri fragment. */
+ private $fragment = '';
+
+ /**
+ * @param string $uri URI to parse
+ */
+ public function __construct($uri = '')
+ {
+ // weak type check to also accept null until we can add scalar type hints
+ if ($uri != '') {
+ $parts = self::parse($uri);
+ if ($parts === false) {
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ }
+ $this->applyParts($parts);
+ }
+ }
+
+ /**
+ * UTF-8 aware \parse_url() replacement.
+ *
+ * The internal function produces broken output for non ASCII domain names
+ * (IDN) when used with locales other than "C".
+ *
+ * On the other hand, cURL understands IDN correctly only when UTF-8 locale
+ * is configured ("C.UTF-8", "en_US.UTF-8", etc.).
+ *
+ * @see https://bugs.php.net/bug.php?id=52923
+ * @see https://www.php.net/manual/en/function.parse-url.php#114817
+ * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
+ *
+ * @param string $url
+ *
+ * @return array|false
+ */
+ private static function parse($url)
+ {
+ // If IPv6
+ $prefix = '';
+ if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
+ $prefix = $matches[1];
+ $url = $matches[2];
+ }
+
+ $encodedUrl = preg_replace_callback(
+ '%[^:/@?&=#]+%usD',
+ static function ($matches) {
+ return urlencode($matches[0]);
+ },
+ $url
+ );
+
+ $result = parse_url($prefix . $encodedUrl);
+
+ if ($result === false) {
+ return false;
+ }
+
+ return array_map('urldecode', $result);
+ }
+
+ public function __toString()
+ {
+ return self::composeComponents(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->path,
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * Composes a URI reference string from its various components.
+ *
+ * Usually this method does not need to be called manually but instead is used indirectly via
+ * `Psr\Http\Message\UriInterface::__toString`.
+ *
+ * PSR-7 UriInterface treats an empty component the same as a missing component as
+ * getQuery(), getFragment() etc. always return a string. This explains the slight
+ * difference to RFC 3986 Section 5.3.
+ *
+ * Another adjustment is that the authority separator is added even when the authority is missing/empty
+ * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
+ * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
+ * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
+ * that format).
+ *
+ * @param string $scheme
+ * @param string $authority
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ *
+ * @return string
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
+ */
+ public static function composeComponents($scheme, $authority, $path, $query, $fragment)
+ {
+ $uri = '';
+
+ // weak type checks to also accept null until we can add scalar type hints
+ if ($scheme != '') {
+ $uri .= $scheme . ':';
+ }
+
+ if ($authority != ''|| $scheme === 'file') {
+ $uri .= '//' . $authority;
+ }
+
+ $uri .= $path;
+
+ if ($query != '') {
+ $uri .= '?' . $query;
+ }
+
+ if ($fragment != '') {
+ $uri .= '#' . $fragment;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether the URI has the default port of the current scheme.
+ *
+ * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
+ * independently of the implementation.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ */
+ public static function isDefaultPort(UriInterface $uri)
+ {
+ return $uri->getPort() === null
+ || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
+ }
+
+ /**
+ * Whether the URI is absolute, i.e. it has a scheme.
+ *
+ * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
+ * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
+ * to another URI, the base URI. Relative references can be divided into several forms:
+ * - network-path references, e.g. '//example.com/path'
+ * - absolute-path references, e.g. '/path'
+ * - relative-path references, e.g. 'subpath'
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @see Uri::isNetworkPathReference
+ * @see Uri::isAbsolutePathReference
+ * @see Uri::isRelativePathReference
+ * @link https://tools.ietf.org/html/rfc3986#section-4
+ */
+ public static function isAbsolute(UriInterface $uri)
+ {
+ return $uri->getScheme() !== '';
+ }
+
+ /**
+ * Whether the URI is a network-path reference.
+ *
+ * A relative reference that begins with two slash characters is termed an network-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isNetworkPathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === '' && $uri->getAuthority() !== '';
+ }
+
+ /**
+ * Whether the URI is a absolute-path reference.
+ *
+ * A relative reference that begins with a single slash character is termed an absolute-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isAbsolutePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && isset($uri->getPath()[0])
+ && $uri->getPath()[0] === '/';
+ }
+
+ /**
+ * Whether the URI is a relative-path reference.
+ *
+ * A relative reference that does not begin with a slash character is termed a relative-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isRelativePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
+ }
+
+ /**
+ * Whether the URI is a same-document reference.
+ *
+ * A same-document reference refers to a URI that is, aside from its fragment
+ * component, identical to the base URI. When no base URI is given, only an empty
+ * URI reference (apart from its fragment) is considered a same-document reference.
+ *
+ * @param UriInterface $uri The URI to check
+ * @param UriInterface|null $base An optional base URI to compare against
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.4
+ */
+ public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
+ {
+ if ($base !== null) {
+ $uri = UriResolver::resolve($base, $uri);
+
+ return ($uri->getScheme() === $base->getScheme())
+ && ($uri->getAuthority() === $base->getAuthority())
+ && ($uri->getPath() === $base->getPath())
+ && ($uri->getQuery() === $base->getQuery());
+ }
+
+ return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
+ }
+
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
+ * @see UriResolver::removeDotSegments
+ */
+ public static function removeDotSegments($path)
+ {
+ return UriResolver::removeDotSegments($path);
+ }
+
+ /**
+ * Converts the relative URI into a new URI that is resolved against the base URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param string|UriInterface $rel Relative URI
+ *
+ * @return UriInterface
+ *
+ * @deprecated since version 1.4. Use UriResolver::resolve instead.
+ * @see UriResolver::resolve
+ */
+ public static function resolve(UriInterface $base, $rel)
+ {
+ if (!($rel instanceof UriInterface)) {
+ $rel = new self($rel);
+ }
+
+ return UriResolver::resolve($base, $rel);
+ }
+
+ /**
+ * Creates a new URI with a specific query string value removed.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Query string key to remove.
+ *
+ * @return UriInterface
+ */
+ public static function withoutQueryValue(UriInterface $uri, $key)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with a specific query string value.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed and replaced with the given key value pair.
+ *
+ * A value of null will set the query string key without a value, e.g. "key"
+ * instead of "key=value".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Key to set.
+ * @param string|null $value Value to set
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValue(UriInterface $uri, $key, $value)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ $result[] = self::generateQueryString($key, $value);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with multiple specific query string values.
+ *
+ * It has the same behavior as withQueryValue() but for an associative array of key => value.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param array $keyValueArray Associative array of key and values
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValues(UriInterface $uri, array $keyValueArray)
+ {
+ $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
+
+ foreach ($keyValueArray as $key => $value) {
+ $result[] = self::generateQueryString($key, $value);
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a URI from a hash of `parse_url` components.
+ *
+ * @param array $parts
+ *
+ * @return UriInterface
+ *
+ * @link http://php.net/manual/en/function.parse-url.php
+ *
+ * @throws \InvalidArgumentException If the components do not form a valid URI.
+ */
+ public static function fromParts(array $parts)
+ {
+ $uri = new self();
+ $uri->applyParts($parts);
+ $uri->validateState();
+
+ return $uri;
+ }
+
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ public function getAuthority()
+ {
+ $authority = $this->host;
+ if ($this->userInfo !== '') {
+ $authority = $this->userInfo . '@' . $authority;
+ }
+
+ if ($this->port !== null) {
+ $authority .= ':' . $this->port;
+ }
+
+ return $authority;
+ }
+
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ public function withScheme($scheme)
+ {
+ $scheme = $this->filterScheme($scheme);
+
+ if ($this->scheme === $scheme) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->scheme = $scheme;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withUserInfo($user, $password = null)
+ {
+ $info = $this->filterUserInfoComponent($user);
+ if ($password !== null) {
+ $info .= ':' . $this->filterUserInfoComponent($password);
+ }
+
+ if ($this->userInfo === $info) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->userInfo = $info;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withHost($host)
+ {
+ $host = $this->filterHost($host);
+
+ if ($this->host === $host) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->host = $host;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPort($port)
+ {
+ $port = $this->filterPort($port);
+
+ if ($this->port === $port) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->port = $port;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPath($path)
+ {
+ $path = $this->filterPath($path);
+
+ if ($this->path === $path) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->path = $path;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withQuery($query)
+ {
+ $query = $this->filterQueryAndFragment($query);
+
+ if ($this->query === $query) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->query = $query;
+
+ return $new;
+ }
+
+ public function withFragment($fragment)
+ {
+ $fragment = $this->filterQueryAndFragment($fragment);
+
+ if ($this->fragment === $fragment) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->fragment = $fragment;
+
+ return $new;
+ }
+
+ /**
+ * Apply parse_url parts to a URI.
+ *
+ * @param array $parts Array of parse_url parts to apply.
+ */
+ private function applyParts(array $parts)
+ {
+ $this->scheme = isset($parts['scheme'])
+ ? $this->filterScheme($parts['scheme'])
+ : '';
+ $this->userInfo = isset($parts['user'])
+ ? $this->filterUserInfoComponent($parts['user'])
+ : '';
+ $this->host = isset($parts['host'])
+ ? $this->filterHost($parts['host'])
+ : '';
+ $this->port = isset($parts['port'])
+ ? $this->filterPort($parts['port'])
+ : null;
+ $this->path = isset($parts['path'])
+ ? $this->filterPath($parts['path'])
+ : '';
+ $this->query = isset($parts['query'])
+ ? $this->filterQueryAndFragment($parts['query'])
+ : '';
+ $this->fragment = isset($parts['fragment'])
+ ? $this->filterQueryAndFragment($parts['fragment'])
+ : '';
+ if (isset($parts['pass'])) {
+ $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
+ }
+
+ $this->removeDefaultPort();
+ }
+
+ /**
+ * @param string $scheme
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the scheme is invalid.
+ */
+ private function filterScheme($scheme)
+ {
+ if (!is_string($scheme)) {
+ throw new \InvalidArgumentException('Scheme must be a string');
+ }
+
+ return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
+ }
+
+ /**
+ * @param string $component
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the user info is invalid.
+ */
+ private function filterUserInfoComponent($component)
+ {
+ if (!is_string($component)) {
+ throw new \InvalidArgumentException('User info must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $component
+ );
+ }
+
+ /**
+ * @param string $host
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the host is invalid.
+ */
+ private function filterHost($host)
+ {
+ if (!is_string($host)) {
+ throw new \InvalidArgumentException('Host must be a string');
+ }
+
+ return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
+ }
+
+ /**
+ * @param int|null $port
+ *
+ * @return int|null
+ *
+ * @throws \InvalidArgumentException If the port is invalid.
+ */
+ private function filterPort($port)
+ {
+ if ($port === null) {
+ return null;
+ }
+
+ $port = (int) $port;
+ if (0 > $port || 0xffff < $port) {
+ throw new \InvalidArgumentException(
+ sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
+ );
+ }
+
+ return $port;
+ }
+
+ /**
+ * @param UriInterface $uri
+ * @param array $keys
+ *
+ * @return array
+ */
+ private static function getFilteredQueryString(UriInterface $uri, array $keys)
+ {
+ $current = $uri->getQuery();
+
+ if ($current === '') {
+ return [];
+ }
+
+ $decodedKeys = array_map('rawurldecode', $keys);
+
+ return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
+ return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
+ });
+ }
+
+ /**
+ * @param string $key
+ * @param string|null $value
+ *
+ * @return string
+ */
+ private static function generateQueryString($key, $value)
+ {
+ // Query string separators ("=", "&") within the key or value need to be encoded
+ // (while preventing double-encoding) before setting the query string. All other
+ // chars that need percent-encoding will be encoded by withQuery().
+ $queryString = strtr($key, self::$replaceQuery);
+
+ if ($value !== null) {
+ $queryString .= '=' . strtr($value, self::$replaceQuery);
+ }
+
+ return $queryString;
+ }
+
+ private function removeDefaultPort()
+ {
+ if ($this->port !== null && self::isDefaultPort($this)) {
+ $this->port = null;
+ }
+ }
+
+ /**
+ * Filters the path of a URI
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the path is invalid.
+ */
+ private function filterPath($path)
+ {
+ if (!is_string($path)) {
+ throw new \InvalidArgumentException('Path must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $path
+ );
+ }
+
+ /**
+ * Filters the query string or fragment of a URI.
+ *
+ * @param string $str
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the query or fragment is invalid.
+ */
+ private function filterQueryAndFragment($str)
+ {
+ if (!is_string($str)) {
+ throw new \InvalidArgumentException('Query and fragment must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $str
+ );
+ }
+
+ private function rawurlencodeMatchZero(array $match)
+ {
+ return rawurlencode($match[0]);
+ }
+
+ private function validateState()
+ {
+ if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
+ $this->host = self::HTTP_DEFAULT_HOST;
+ }
+
+ if ($this->getAuthority() === '') {
+ if (0 === strpos($this->path, '//')) {
+ throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
+ }
+ if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
+ throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
+ }
+ } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
+ @trigger_error(
+ 'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
+ 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
+ E_USER_DEPRECATED
+ );
+ $this->path = '/' . $this->path;
+ //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UriNormalizer.php b/vendor/guzzlehttp/psr7/src/UriNormalizer.php
new file mode 100644
index 0000000..81419ea
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/UriNormalizer.php
@@ -0,0 +1,219 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Provides methods to normalize and compare URIs.
+ *
+ * @author Tobias Schultze
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6
+ */
+final class UriNormalizer
+{
+ /**
+ * Default normalizations which only include the ones that preserve semantics.
+ *
+ * self::CAPITALIZE_PERCENT_ENCODING | self::DECODE_UNRESERVED_CHARACTERS | self::CONVERT_EMPTY_PATH |
+ * self::REMOVE_DEFAULT_HOST | self::REMOVE_DEFAULT_PORT | self::REMOVE_DOT_SEGMENTS
+ */
+ const PRESERVING_NORMALIZATIONS = 63;
+
+ /**
+ * All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
+ *
+ * Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b
+ */
+ const CAPITALIZE_PERCENT_ENCODING = 1;
+
+ /**
+ * Decodes percent-encoded octets of unreserved characters.
+ *
+ * For consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39),
+ * hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers and,
+ * when found in a URI, should be decoded to their corresponding unreserved characters by URI normalizers.
+ *
+ * Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/
+ */
+ const DECODE_UNRESERVED_CHARACTERS = 2;
+
+ /**
+ * Converts the empty path to "/" for http and https URIs.
+ *
+ * Example: http://example.org → http://example.org/
+ */
+ const CONVERT_EMPTY_PATH = 4;
+
+ /**
+ * Removes the default host of the given URI scheme from the URI.
+ *
+ * Only the "file" scheme defines the default host "localhost".
+ * All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile`
+ * are equivalent according to RFC 3986. The first format is not accepted
+ * by PHPs stream functions and thus already normalized implicitly to the
+ * second format in the Uri class. See `GuzzleHttp\Psr7\Uri::composeComponents`.
+ *
+ * Example: file://localhost/myfile → file:///myfile
+ */
+ const REMOVE_DEFAULT_HOST = 8;
+
+ /**
+ * Removes the default port of the given URI scheme from the URI.
+ *
+ * Example: http://example.org:80/ → http://example.org/
+ */
+ const REMOVE_DEFAULT_PORT = 16;
+
+ /**
+ * Removes unnecessary dot-segments.
+ *
+ * Dot-segments in relative-path references are not removed as it would
+ * change the semantics of the URI reference.
+ *
+ * Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html
+ */
+ const REMOVE_DOT_SEGMENTS = 32;
+
+ /**
+ * Paths which include two or more adjacent slashes are converted to one.
+ *
+ * Webservers usually ignore duplicate slashes and treat those URIs equivalent.
+ * But in theory those URIs do not need to be equivalent. So this normalization
+ * may change the semantics. Encoded slashes (%2F) are not removed.
+ *
+ * Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html
+ */
+ const REMOVE_DUPLICATE_SLASHES = 64;
+
+ /**
+ * Sort query parameters with their values in alphabetical order.
+ *
+ * However, the order of parameters in a URI may be significant (this is not defined by the standard).
+ * So this normalization is not safe and may change the semantics of the URI.
+ *
+ * Example: ?lang=en&article=fred → ?article=fred&lang=en
+ *
+ * Note: The sorting is neither locale nor Unicode aware (the URI query does not get decoded at all) as the
+ * purpose is to be able to compare URIs in a reproducible way, not to have the params sorted perfectly.
+ */
+ const SORT_QUERY_PARAMETERS = 128;
+
+ /**
+ * Returns a normalized URI.
+ *
+ * The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
+ * This methods adds additional normalizations that can be configured with the $flags parameter.
+ *
+ * PSR-7 UriInterface cannot distinguish between an empty component and a missing component as
+ * getQuery(), getFragment() etc. always return a string. This means the URIs "/?#" and "/" are
+ * treated equivalent which is not necessarily true according to RFC 3986. But that difference
+ * is highly uncommon in reality. So this potential normalization is implied in PSR-7 as well.
+ *
+ * @param UriInterface $uri The URI to normalize
+ * @param int $flags A bitmask of normalizations to apply, see constants
+ *
+ * @return UriInterface The normalized URI
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6.2
+ */
+ public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS)
+ {
+ if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {
+ $uri = self::capitalizePercentEncoding($uri);
+ }
+
+ if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {
+ $uri = self::decodeUnreservedCharacters($uri);
+ }
+
+ if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&
+ ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
+ ) {
+ $uri = $uri->withPath('/');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
+ $uri = $uri->withHost('');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
+ $uri = $uri->withPort(null);
+ }
+
+ if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
+ $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
+ }
+
+ if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
+ $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
+ }
+
+ if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
+ $queryKeyValues = explode('&', $uri->getQuery());
+ sort($queryKeyValues);
+ $uri = $uri->withQuery(implode('&', $queryKeyValues));
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether two URIs can be considered equivalent.
+ *
+ * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
+ * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
+ * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
+ * relative references does not mean anything.
+ *
+ * @param UriInterface $uri1 An URI to compare
+ * @param UriInterface $uri2 An URI to compare
+ * @param int $normalizations A bitmask of normalizations to apply, see constants
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6.1
+ */
+ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)
+ {
+ return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
+ }
+
+ private static function capitalizePercentEncoding(UriInterface $uri)
+ {
+ $regex = '/(?:%[A-Fa-f0-9]{2})++/';
+
+ $callback = function (array $match) {
+ return strtoupper($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private static function decodeUnreservedCharacters(UriInterface $uri)
+ {
+ $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';
+
+ $callback = function (array $match) {
+ return rawurldecode($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UriResolver.php b/vendor/guzzlehttp/psr7/src/UriResolver.php
new file mode 100644
index 0000000..a3cb15d
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/UriResolver.php
@@ -0,0 +1,222 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Resolves a URI reference in the context of a base URI and the opposite way.
+ *
+ * @author Tobias Schultze
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5
+ */
+final class UriResolver
+{
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+ public static function removeDotSegments($path)
+ {
+ if ($path === '' || $path === '/') {
+ return $path;
+ }
+
+ $results = [];
+ $segments = explode('/', $path);
+ foreach ($segments as $segment) {
+ if ($segment === '..') {
+ array_pop($results);
+ } elseif ($segment !== '.') {
+ $results[] = $segment;
+ }
+ }
+
+ $newPath = implode('/', $results);
+
+ if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
+ // Re-add the leading slash if necessary for cases like "/.."
+ $newPath = '/' . $newPath;
+ } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
+ // Add the trailing slash if necessary
+ // If newPath is not empty, then $segment must be set and is the last segment from the foreach
+ $newPath .= '/';
+ }
+
+ return $newPath;
+ }
+
+ /**
+ * Converts the relative URI into a new URI that is resolved against the base URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param UriInterface $rel Relative URI
+ *
+ * @return UriInterface
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2
+ */
+ public static function resolve(UriInterface $base, UriInterface $rel)
+ {
+ if ((string) $rel === '') {
+ // we can simply return the same base URI instance for this same-document reference
+ return $base;
+ }
+
+ if ($rel->getScheme() != '') {
+ return $rel->withPath(self::removeDotSegments($rel->getPath()));
+ }
+
+ if ($rel->getAuthority() != '') {
+ $targetAuthority = $rel->getAuthority();
+ $targetPath = self::removeDotSegments($rel->getPath());
+ $targetQuery = $rel->getQuery();
+ } else {
+ $targetAuthority = $base->getAuthority();
+ if ($rel->getPath() === '') {
+ $targetPath = $base->getPath();
+ $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
+ } else {
+ if ($rel->getPath()[0] === '/') {
+ $targetPath = $rel->getPath();
+ } else {
+ if ($targetAuthority != '' && $base->getPath() === '') {
+ $targetPath = '/' . $rel->getPath();
+ } else {
+ $lastSlashPos = strrpos($base->getPath(), '/');
+ if ($lastSlashPos === false) {
+ $targetPath = $rel->getPath();
+ } else {
+ $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
+ }
+ }
+ }
+ $targetPath = self::removeDotSegments($targetPath);
+ $targetQuery = $rel->getQuery();
+ }
+ }
+
+ return new Uri(Uri::composeComponents(
+ $base->getScheme(),
+ $targetAuthority,
+ $targetPath,
+ $targetQuery,
+ $rel->getFragment()
+ ));
+ }
+
+ /**
+ * Returns the target URI as a relative reference from the base URI.
+ *
+ * This method is the counterpart to resolve():
+ *
+ * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
+ *
+ * One use-case is to use the current request URI as base URI and then generate relative links in your documents
+ * to reduce the document size or offer self-contained downloadable document archives.
+ *
+ * $base = new Uri('http://example.com/a/b/');
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
+ * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
+ *
+ * This method also accepts a target that is already relative and will try to relativize it further. Only a
+ * relative-path reference will be returned as-is.
+ *
+ * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
+ *
+ * @param UriInterface $base Base URI
+ * @param UriInterface $target Target URI
+ *
+ * @return UriInterface The relative URI reference
+ */
+ public static function relativize(UriInterface $base, UriInterface $target)
+ {
+ if ($target->getScheme() !== '' &&
+ ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
+ ) {
+ return $target;
+ }
+
+ if (Uri::isRelativePathReference($target)) {
+ // As the target is already highly relative we return it as-is. It would be possible to resolve
+ // the target with `$target = self::resolve($base, $target);` and then try make it more relative
+ // by removing a duplicate query. But let's not do that automatically.
+ return $target;
+ }
+
+ if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
+ return $target->withScheme('');
+ }
+
+ // We must remove the path before removing the authority because if the path starts with two slashes, the URI
+ // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
+ // invalid.
+ $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
+
+ if ($base->getPath() !== $target->getPath()) {
+ return $emptyPathUri->withPath(self::getRelativePath($base, $target));
+ }
+
+ if ($base->getQuery() === $target->getQuery()) {
+ // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
+ return $emptyPathUri->withQuery('');
+ }
+
+ // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
+ // inherit the base query component when resolving.
+ if ($target->getQuery() === '') {
+ $segments = explode('/', $target->getPath());
+ $lastSegment = end($segments);
+
+ return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
+ }
+
+ return $emptyPathUri;
+ }
+
+ private static function getRelativePath(UriInterface $base, UriInterface $target)
+ {
+ $sourceSegments = explode('/', $base->getPath());
+ $targetSegments = explode('/', $target->getPath());
+ array_pop($sourceSegments);
+ $targetLastSegment = array_pop($targetSegments);
+ foreach ($sourceSegments as $i => $segment) {
+ if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
+ unset($sourceSegments[$i], $targetSegments[$i]);
+ } else {
+ break;
+ }
+ }
+ $targetSegments[] = $targetLastSegment;
+ $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
+
+ // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
+ // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
+ // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
+ if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
+ $relativePath = "./$relativePath";
+ } elseif ('/' === $relativePath[0]) {
+ if ($base->getAuthority() != '' && $base->getPath() === '') {
+ // In this case an extra slash is added by resolve() automatically. So we must not add one here.
+ $relativePath = ".$relativePath";
+ } else {
+ $relativePath = "./$relativePath";
+ }
+ }
+
+ return $relativePath;
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Utils.php b/vendor/guzzlehttp/psr7/src/Utils.php
new file mode 100644
index 0000000..6b6c8cc
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/Utils.php
@@ -0,0 +1,428 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+final class Utils
+{
+ /**
+ * Remove the items given by the keys, case insensitively from the data.
+ *
+ * @param iterable<string> $keys
+ *
+ * @return array
+ */
+ public static function caselessRemove($keys, array $data)
+ {
+ $result = [];
+
+ foreach ($keys as &$key) {
+ $key = strtolower($key);
+ }
+
+ foreach ($data as $k => $v) {
+ if (!in_array(strtolower($k), $keys)) {
+ $result[$k] = $v;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
+ {
+ $bufferSize = 8192;
+
+ if ($maxLen === -1) {
+ while (!$source->eof()) {
+ if (!$dest->write($source->read($bufferSize))) {
+ break;
+ }
+ }
+ } else {
+ $remaining = $maxLen;
+ while ($remaining > 0 && !$source->eof()) {
+ $buf = $source->read(min($bufferSize, $remaining));
+ $len = strlen($buf);
+ if (!$len) {
+ break;
+ }
+ $remaining -= $len;
+ $dest->write($buf);
+ }
+ }
+ }
+
+ /**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @return string
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function copyToString(StreamInterface $stream, $maxLen = -1)
+ {
+ $buffer = '';
+
+ if ($maxLen === -1) {
+ while (!$stream->eof()) {
+ $buf = $stream->read(1048576);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ }
+ return $buffer;
+ }
+
+ $len = 0;
+ while (!$stream->eof() && $len < $maxLen) {
+ $buf = $stream->read($maxLen - $len);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ $len = strlen($buffer);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Calculate a hash of a stream.
+ *
+ * This method reads the entire stream to calculate a rolling hash, based
+ * on PHP's `hash_init` functions.
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function hash(StreamInterface $stream, $algo, $rawOutput = false)
+ {
+ $pos = $stream->tell();
+
+ if ($pos > 0) {
+ $stream->rewind();
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->eof()) {
+ hash_update($ctx, $stream->read(1048576));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+ }
+
+ /**
+ * Clone and modify a request with the given changes.
+ *
+ * This method is useful for reducing the number of clones needed to mutate
+ * a message.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ */
+ public static function modifyRequest(RequestInterface $request, array $changes)
+ {
+ if (!$changes) {
+ return $request;
+ }
+
+ $headers = $request->getHeaders();
+
+ if (!isset($changes['uri'])) {
+ $uri = $request->getUri();
+ } else {
+ // Remove the host header if one is on the URI
+ if ($host = $changes['uri']->getHost()) {
+ $changes['set_headers']['Host'] = $host;
+
+ if ($port = $changes['uri']->getPort()) {
+ $standardPorts = ['http' => 80, 'https' => 443];
+ $scheme = $changes['uri']->getScheme();
+ if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
+ $changes['set_headers']['Host'] .= ':' . $port;
+ }
+ }
+ }
+ $uri = $changes['uri'];
+ }
+
+ if (!empty($changes['remove_headers'])) {
+ $headers = self::caselessRemove($changes['remove_headers'], $headers);
+ }
+
+ if (!empty($changes['set_headers'])) {
+ $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);
+ $headers = $changes['set_headers'] + $headers;
+ }
+
+ if (isset($changes['query'])) {
+ $uri = $uri->withQuery($changes['query']);
+ }
+
+ if ($request instanceof ServerRequestInterface) {
+ $new = (new ServerRequest(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion(),
+ $request->getServerParams()
+ ))
+ ->withParsedBody($request->getParsedBody())
+ ->withQueryParams($request->getQueryParams())
+ ->withCookieParams($request->getCookieParams())
+ ->withUploadedFiles($request->getUploadedFiles());
+
+ foreach ($request->getAttributes() as $key => $value) {
+ $new = $new->withAttribute($key, $value);
+ }
+
+ return $new;
+ }
+
+ return new Request(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion()
+ );
+ }
+
+ /**
+ * Read a line from the stream up to the maximum allowed buffer length.
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int|null $maxLength Maximum buffer length
+ *
+ * @return string
+ */
+ public static function readLine(StreamInterface $stream, $maxLength = null)
+ {
+ $buffer = '';
+ $size = 0;
+
+ while (!$stream->eof()) {
+ // Using a loose equality here to match on '' and false.
+ if (null == ($byte = $stream->read(1))) {
+ return $buffer;
+ }
+ $buffer .= $byte;
+ // Break when a new line is found or the max length - 1 is reached
+ if ($byte === "\n" || ++$size === $maxLength - 1) {
+ break;
+ }
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * This method accepts the following `$resource` types:
+ * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
+ * - `string`: Creates a stream object that uses the given string as the contents.
+ * - `resource`: Creates a stream object that wraps the given PHP stream resource.
+ * - `Iterator`: If the provided value implements `Iterator`, then a read-only
+ * stream object will be created that wraps the given iterable. Each time the
+ * stream is read from, data from the iterator will fill a buffer and will be
+ * continuously called until the buffer is equal to the requested read size.
+ * Subsequent read calls will first read from the buffer and then call `next`
+ * on the underlying iterator until it is exhausted.
+ * - `object` with `__toString()`: If the object has the `__toString()` method,
+ * the object will be cast to a string and then a stream will be returned that
+ * uses the string value.
+ * - `NULL`: When `null` is passed, an empty stream object is returned.
+ * - `callable` When a callable is passed, a read-only stream object will be
+ * created that invokes the given callable. The callable is invoked with the
+ * number of suggested bytes to read. The callable can return any number of
+ * bytes, but MUST return `false` when there is no more data to return. The
+ * stream object that wraps the callable will invoke the callable until the
+ * number of requested bytes are available. Any additional bytes will be
+ * buffered and used in subsequent reads.
+ *
+ * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return StreamInterface
+ *
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ */
+ public static function streamFor($resource = '', array $options = [])
+ {
+ if (is_scalar($resource)) {
+ $stream = self::tryFopen('php://temp', 'r+');
+ if ($resource !== '') {
+ fwrite($stream, $resource);
+ fseek($stream, 0);
+ }
+ return new Stream($stream, $options);
+ }
+
+ switch (gettype($resource)) {
+ case 'resource':
+ /*
+ * The 'php://input' is a special stream with quirks and inconsistencies.
+ * We avoid using that stream by reading it into php://temp
+ */
+ $metaData = \stream_get_meta_data($resource);
+ if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') {
+ $stream = self::tryFopen('php://temp', 'w+');
+ fwrite($stream, stream_get_contents($resource));
+ fseek($stream, 0);
+ $resource = $stream;
+ }
+ return new Stream($resource, $options);
+ case 'object':
+ if ($resource instanceof StreamInterface) {
+ return $resource;
+ } elseif ($resource instanceof \Iterator) {
+ return new PumpStream(function () use ($resource) {
+ if (!$resource->valid()) {
+ return false;
+ }
+ $result = $resource->current();
+ $resource->next();
+ return $result;
+ }, $options);
+ } elseif (method_exists($resource, '__toString')) {
+ return Utils::streamFor((string) $resource, $options);
+ }
+ break;
+ case 'NULL':
+ return new Stream(self::tryFopen('php://temp', 'r+'), $options);
+ }
+
+ if (is_callable($resource)) {
+ return new PumpStream($resource, $options);
+ }
+
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
+ }
+
+ /**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ *
+ * @throws \RuntimeException if the file cannot be opened
+ */
+ public static function tryFopen($filename, $mode)
+ {
+ $ex = null;
+ set_error_handler(function () use ($filename, $mode, &$ex) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open "%s" using mode "%s": %s',
+ $filename,
+ $mode,
+ func_get_args()[1]
+ ));
+
+ return true;
+ });
+
+ try {
+ $handle = fopen($filename, $mode);
+ } catch (\Throwable $e) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open "%s" using mode "%s": %s',
+ $filename,
+ $mode,
+ $e->getMessage()
+ ), 0, $e);
+ }
+
+ restore_error_handler();
+
+ if ($ex) {
+ /** @var $ex \RuntimeException */
+ throw $ex;
+ }
+
+ return $handle;
+ }
+
+ /**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or UriInterface and returns a
+ * UriInterface for the given value. If the value is already a
+ * UriInterface, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function uriFor($uri)
+ {
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ }
+
+ if (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/functions.php b/vendor/guzzlehttp/psr7/src/functions.php
new file mode 100644
index 0000000..b0901fa
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/functions.php
@@ -0,0 +1,422 @@
+<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Returns the string representation of an HTTP message.
+ *
+ * @param MessageInterface $message Message to convert to a string.
+ *
+ * @return string
+ *
+ * @deprecated str will be removed in guzzlehttp/psr7:2.0. Use Message::toString instead.
+ */
+function str(MessageInterface $message)
+{
+ return Message::toString($message);
+}
+
+/**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or UriInterface and returns a
+ * UriInterface for the given value. If the value is already a
+ * UriInterface, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @deprecated uri_for will be removed in guzzlehttp/psr7:2.0. Use Utils::uriFor instead.
+ */
+function uri_for($uri)
+{
+ return Utils::uriFor($uri);
+}
+
+/**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * This method accepts the following `$resource` types:
+ * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
+ * - `string`: Creates a stream object that uses the given string as the contents.
+ * - `resource`: Creates a stream object that wraps the given PHP stream resource.
+ * - `Iterator`: If the provided value implements `Iterator`, then a read-only
+ * stream object will be created that wraps the given iterable. Each time the
+ * stream is read from, data from the iterator will fill a buffer and will be
+ * continuously called until the buffer is equal to the requested read size.
+ * Subsequent read calls will first read from the buffer and then call `next`
+ * on the underlying iterator until it is exhausted.
+ * - `object` with `__toString()`: If the object has the `__toString()` method,
+ * the object will be cast to a string and then a stream will be returned that
+ * uses the string value.
+ * - `NULL`: When `null` is passed, an empty stream object is returned.
+ * - `callable` When a callable is passed, a read-only stream object will be
+ * created that invokes the given callable. The callable is invoked with the
+ * number of suggested bytes to read. The callable can return any number of
+ * bytes, but MUST return `false` when there is no more data to return. The
+ * stream object that wraps the callable will invoke the callable until the
+ * number of requested bytes are available. Any additional bytes will be
+ * buffered and used in subsequent reads.
+ *
+ * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return StreamInterface
+ *
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ *
+ * @deprecated stream_for will be removed in guzzlehttp/psr7:2.0. Use Utils::streamFor instead.
+ */
+function stream_for($resource = '', array $options = [])
+{
+ return Utils::streamFor($resource, $options);
+}
+
+/**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair data
+ * of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ *
+ * @deprecated parse_header will be removed in guzzlehttp/psr7:2.0. Use Header::parse instead.
+ */
+function parse_header($header)
+{
+ return Header::parse($header);
+}
+
+/**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ *
+ * @deprecated normalize_header will be removed in guzzlehttp/psr7:2.0. Use Header::normalize instead.
+ */
+function normalize_header($header)
+{
+ return Header::normalize($header);
+}
+
+/**
+ * Clone and modify a request with the given changes.
+ *
+ * This method is useful for reducing the number of clones needed to mutate a
+ * message.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ *
+ * @deprecated modify_request will be removed in guzzlehttp/psr7:2.0. Use Utils::modifyRequest instead.
+ */
+function modify_request(RequestInterface $request, array $changes)
+{
+ return Utils::modifyRequest($request, $changes);
+}
+
+/**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()` returns a
+ * value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ *
+ * @deprecated rewind_body will be removed in guzzlehttp/psr7:2.0. Use Message::rewindBody instead.
+ */
+function rewind_body(MessageInterface $message)
+{
+ Message::rewindBody($message);
+}
+
+/**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ *
+ * @throws \RuntimeException if the file cannot be opened
+ *
+ * @deprecated try_fopen will be removed in guzzlehttp/psr7:2.0. Use Utils::tryFopen instead.
+ */
+function try_fopen($filename, $mode)
+{
+ return Utils::tryFopen($filename, $mode);
+}
+
+/**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @return string
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated copy_to_string will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToString instead.
+ */
+function copy_to_string(StreamInterface $stream, $maxLen = -1)
+{
+ return Utils::copyToString($stream, $maxLen);
+}
+
+/**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated copy_to_stream will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToStream instead.
+ */
+function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
+{
+ return Utils::copyToStream($source, $dest, $maxLen);
+}
+
+/**
+ * Calculate a hash of a stream.
+ *
+ * This method reads the entire stream to calculate a rolling hash, based on
+ * PHP's `hash_init` functions.
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated hash will be removed in guzzlehttp/psr7:2.0. Use Utils::hash instead.
+ */
+function hash(StreamInterface $stream, $algo, $rawOutput = false)
+{
+ return Utils::hash($stream, $algo, $rawOutput);
+}
+
+/**
+ * Read a line from the stream up to the maximum allowed buffer length.
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int|null $maxLength Maximum buffer length
+ *
+ * @return string
+ *
+ * @deprecated readline will be removed in guzzlehttp/psr7:2.0. Use Utils::readLine instead.
+ */
+function readline(StreamInterface $stream, $maxLength = null)
+{
+ return Utils::readLine($stream, $maxLength);
+}
+
+/**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ *
+ * @deprecated parse_request will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequest instead.
+ */
+function parse_request($message)
+{
+ return Message::parseRequest($message);
+}
+
+/**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ *
+ * @deprecated parse_response will be removed in guzzlehttp/psr7:2.0. Use Message::parseResponse instead.
+ */
+function parse_response($message)
+{
+ return Message::parseResponse($message);
+}
+
+/**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key value
+ * pair will become an array. This function does not parse nested PHP style
+ * arrays into an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed
+ * into `['foo[a]' => '1', 'foo[b]' => '2'])`.
+ *
+ * @param string $str Query string to parse
+ * @param int|bool $urlEncoding How the query string is encoded
+ *
+ * @return array
+ *
+ * @deprecated parse_query will be removed in guzzlehttp/psr7:2.0. Use Query::parse instead.
+ */
+function parse_query($str, $urlEncoding = true)
+{
+ return Query::parse($str, $urlEncoding);
+}
+
+/**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of `parse_query()` to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like `http_build_query()` would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ *
+ * @return string
+ *
+ * @deprecated build_query will be removed in guzzlehttp/psr7:2.0. Use Query::build instead.
+ */
+function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
+{
+ return Query::build($params, $encoding);
+}
+
+/**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param string $filename
+ *
+ * @return string|null
+ *
+ * @deprecated mimetype_from_filename will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromFilename instead.
+ */
+function mimetype_from_filename($filename)
+{
+ return MimeType::fromFilename($filename);
+}
+
+/**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param $extension string The file extension.
+ *
+ * @return string|null
+ *
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ * @deprecated mimetype_from_extension will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromExtension instead.
+ */
+function mimetype_from_extension($extension)
+{
+ return MimeType::fromExtension($extension);
+}
+
+/**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ *
+ * @internal
+ *
+ * @deprecated _parse_message will be removed in guzzlehttp/psr7:2.0. Use Message::parseMessage instead.
+ */
+function _parse_message($message)
+{
+ return Message::parseMessage($message);
+}
+
+/**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ *
+ * @internal
+ *
+ * @deprecated _parse_request_uri will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequestUri instead.
+ */
+function _parse_request_uri($path, array $headers)
+{
+ return Message::parseRequestUri($path, $headers);
+}
+
+/**
+ * Get a short summary of the message body.
+ *
+ * Will return `null` if the response is not printable.
+ *
+ * @param MessageInterface $message The message to get the body summary
+ * @param int $truncateAt The maximum allowed size of the summary
+ *
+ * @return string|null
+ *
+ * @deprecated get_message_body_summary will be removed in guzzlehttp/psr7:2.0. Use Message::bodySummary instead.
+ */
+function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
+{
+ return Message::bodySummary($message, $truncateAt);
+}
+
+/**
+ * Remove the items given by the keys, case insensitively from the data.
+ *
+ * @param iterable<string> $keys
+ *
+ * @return array
+ *
+ * @internal
+ *
+ * @deprecated _caseless_remove will be removed in guzzlehttp/psr7:2.0. Use Utils::caselessRemove instead.
+ */
+function _caseless_remove($keys, array $data)
+{
+ return Utils::caselessRemove($keys, $data);
+}
diff --git a/vendor/guzzlehttp/psr7/src/functions_include.php b/vendor/guzzlehttp/psr7/src/functions_include.php
new file mode 100644
index 0000000..96a4a83
--- /dev/null
+++ b/vendor/guzzlehttp/psr7/src/functions_include.php
@@ -0,0 +1,6 @@
+<?php
+
+// Don't redefine the functions if included multiple times.
+if (!function_exists('GuzzleHttp\Psr7\str')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/jfcherng/php-color-output/LICENSE b/vendor/jfcherng/php-color-output/LICENSE
new file mode 100644
index 0000000..e16b553
--- /dev/null
+++ b/vendor/jfcherng/php-color-output/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018-2019 Jack Cherng (jfcherng)
+
+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/jfcherng/php-color-output/composer.json b/vendor/jfcherng/php-color-output/composer.json
new file mode 100644
index 0000000..4d5eb4c
--- /dev/null
+++ b/vendor/jfcherng/php-color-output/composer.json
@@ -0,0 +1,57 @@
+{
+ "name": "jfcherng/php-color-output",
+ "description": "Make your PHP command-line application colorful.",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "keywords": [
+ "command-line",
+ "color",
+ "ansi-colors",
+ "str-color"
+ ],
+ "minimum-stability": "beta",
+ "prefer-stable": true,
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ },
+ "files": [
+ "src/helpers.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Jfcherng\\Utility\\Test\\": "tests/"
+ }
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.15",
+ "phan/phan": "^2.2",
+ "phpunit/phpunit": "^7.2 || ^8.2 || ^9",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "scripts": {
+ "analyze": [
+ "phan --color",
+ "phpcs --colors -n"
+ ],
+ "fix": [
+ "php-cs-fixer fix --verbose"
+ ],
+ "test": [
+ "phpunit --verbose"
+ ]
+ }
+}
diff --git a/vendor/jfcherng/php-color-output/demo.php b/vendor/jfcherng/php-color-output/demo.php
new file mode 100644
index 0000000..3c08598
--- /dev/null
+++ b/vendor/jfcherng/php-color-output/demo.php
@@ -0,0 +1,26 @@
+<?php
+
+include __DIR__ . '/vendor/autoload.php';
+
+// colors in a string using a comma as the delimiter
+echo str_cli_color('foo', 'f_light_cyan, b_yellow'); // "\033[1;36;43mfoo\033[0m"
+
+echo \PHP_EOL;
+
+// colors in an array
+echo str_cli_color('foo', ['f_white', 'b_magenta']); // "\033[1;37;45mfoo\033[0m"
+
+echo \PHP_EOL;
+
+// do not auto reset color at the end of string
+echo str_cli_color('foo', ['f_red', 'b_green', 'b', 'blk'], false); // "\033[31;42;1;5mfoo"
+
+// manually add color reset
+echo str_cli_color('', 'reset'); // "\033[0m"
+
+echo \PHP_EOL;
+
+// remove all color codes from a string
+echo str_cli_nocolor("\033[31;42;5mfoo\033[0mbar"); // "foobar"
+
+echo \PHP_EOL;
diff --git a/vendor/jfcherng/php-color-output/src/CliColor.php b/vendor/jfcherng/php-color-output/src/CliColor.php
new file mode 100644
index 0000000..6004b6c
--- /dev/null
+++ b/vendor/jfcherng/php-color-output/src/CliColor.php
@@ -0,0 +1,224 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Utility;
+
+/**
+ * Make your PHP command-line application colorful.
+ *
+ * @see https://en.wikipedia.org/wiki/ANSI_escape_code
+ *
+ * @author Jack Cherng <jfcherng@gmail.com>
+ */
+final class CliColor
+{
+ const COLOR_BEGIN = "\033[";
+ const COLOR_END = 'm';
+
+ const COLOR_BEGIN_REGEX = "\033\\[";
+ const COLOR_END_REGEX = 'm';
+
+ /**
+ * @var array the color map
+ */
+ private static $colorMap = [
+ // background
+ 'b_black' => '40',
+ 'b_blue' => '44',
+ 'b_cyan' => '46',
+ 'b_green' => '42',
+ 'b_light_gray' => '47',
+ 'b_magenta' => '45',
+ 'b_red' => '41',
+ 'b_yellow' => '43',
+
+ // foreground
+ 'f_black' => '30',
+ 'f_blue' => '34',
+ 'f_brown' => '33',
+ 'f_cyan' => '36',
+ 'f_green' => '32',
+ 'f_light_gray' => '37',
+ 'f_normal' => '39',
+ 'f_purple' => '35',
+ 'f_red' => '31',
+
+ // compound
+ 'f_dark_gray' => '1;30',
+ 'f_light_blue' => '1;34',
+ 'f_light_cyan' => '1;36',
+ 'f_light_green' => '1;32',
+ 'f_light_purple' => '1;35',
+ 'f_light_red' => '1;31',
+ 'f_white' => '1;37',
+ 'f_yellow' => '1;33',
+
+ // special
+ 'blink' => '5',
+ 'bold' => '1',
+ 'dim' => '2',
+ 'hidden' => '8',
+ 'reset' => '0',
+ 'reverse' => '7',
+ 'underline' => '4',
+
+ // alias
+ 'b' => 'bold',
+ 'blk' => 'blink',
+ 'h' => 'hidden',
+ 'rev' => 'reverse',
+ 'rst' => 'reset',
+ 'u' => 'underline',
+
+ // regex for color codes
+ 'regex_any' => '(?:[0-9]++;?)++',
+ ];
+
+ /**
+ * Get the color map.
+ *
+ * @return array the color map
+ */
+ public static function getColorMap(): array
+ {
+ return self::$colorMap;
+ }
+
+ /**
+ * Make a string colorful.
+ *
+ * @param string $str the string
+ * @param string|string[] $colors the colors
+ * @param bool $reset reset color at the end of the string?
+ *
+ * @return string the colored string
+ */
+ public static function color(string $str, $colors = [], bool $reset = true): string
+ {
+ // always convert $colors into an array
+ if (\is_string($colors)) {
+ $colors = \explode(',', $colors);
+ }
+
+ $colored = self::getColorCode($colors) . $str;
+
+ if ($reset) {
+ $colored .= self::getColorCode(['reset']);
+ }
+
+ return self::simplifyColoredString($colored);
+ }
+
+ /**
+ * Remove all colors from a string.
+ *
+ * @param string $str the string
+ *
+ * @return string the string without colors
+ */
+ public static function noColor(string $str): string
+ {
+ return \preg_replace(
+ '~' . self::getColorCode(['regex_any'], true) . '~uS',
+ '',
+ $str
+ );
+ }
+
+ /**
+ * Get the color code from given colors.
+ *
+ * @param array $colors the colors
+ * @param bool $returnRegex return as an regex segment
+ *
+ * @return string the color code
+ */
+ private static function getColorCode(array $colors, bool $returnRegex = false): string
+ {
+ $colors = self::sanitizeColors($colors);
+
+ if (empty($colors)) {
+ return '';
+ }
+
+ // convert color into color code
+ $colorCodes = \array_map(
+ function (string $color): string {
+ // resolve color alias
+ while (isset(self::$colorMap[$color])) {
+ $color = self::$colorMap[$color];
+ }
+
+ return $color;
+ },
+ $colors
+ );
+
+ $closures = $returnRegex
+ ? [self::COLOR_BEGIN_REGEX, self::COLOR_END_REGEX]
+ : [self::COLOR_BEGIN, self::COLOR_END];
+
+ return $closures[0] . \implode(';', $colorCodes) . $closures[1];
+ }
+
+ /**
+ * Sanitize colors.
+ *
+ * @param array $colors the colors
+ *
+ * @return array the sanitized colors
+ */
+ private static function sanitizeColors(array $colors): array
+ {
+ return self::listUnique(\array_filter(
+ \array_map('trim', $colors),
+ function (string $color): bool {
+ return isset(self::$colorMap[$color]);
+ }
+ ));
+ }
+
+ /**
+ * Simplify the colored string.
+ *
+ * @param string $str the colored string
+ *
+ * @return string the simplified colored string
+ */
+ private static function simplifyColoredString(string $str): string
+ {
+ // replace multiple consecutive resets with a single reset
+ $str = \preg_replace(
+ '~(' . self::getColorCode(['reset'], true) . '){2,}~uS',
+ '$1',
+ $str
+ );
+
+ // remove colors for an emtpy string
+ $str = \preg_replace(
+ (
+ '~' .
+ '(' . self::getColorCode(['regex_any'], true) . ')' .
+ '(' . self::getColorCode(['reset'], true) . ')' .
+ '~uS'
+ ),
+ '$2',
+ $str
+ );
+
+ return $str;
+ }
+
+ /**
+ * The fastest array_unique() implementation for a non-associative array AFAIK.
+ *
+ * @see https://stackoverflow.com/questions/8321620/array-unique-vs-array-flip
+ *
+ * @param array $array the array
+ */
+ private static function listUnique(array $array): array
+ {
+ return \array_keys(\array_count_values($array));
+ }
+}
diff --git a/vendor/jfcherng/php-color-output/src/helpers.php b/vendor/jfcherng/php-color-output/src/helpers.php
new file mode 100644
index 0000000..b93d4e6
--- /dev/null
+++ b/vendor/jfcherng/php-color-output/src/helpers.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+if (!\function_exists('str_cli_color')) {
+ /**
+ * Make a string colorful.
+ *
+ * A global alias to \Jfcherng\Utility\CliColor::color.
+ *
+ * @param string $str the string
+ * @param array|string $colors the colors
+ * @param bool $autoReset automatically reset at the end of the string?
+ *
+ * @return string the colored string
+ */
+ function str_cli_color(string $str, $colors = [], bool $autoReset = true): string
+ {
+ return \Jfcherng\Utility\CliColor::color($str, $colors, $autoReset);
+ }
+}
+
+if (!\function_exists('str_cli_nocolor')) {
+ /**
+ * Remove all colors from a string.
+ *
+ * A global alias to \Jfcherng\Utility\CliColor::noColor
+ *
+ * @param string $str the string
+ *
+ * @return string the string without colors
+ */
+ function str_cli_nocolor(string $str): string
+ {
+ return \Jfcherng\Utility\CliColor::noColor($str);
+ }
+}
diff --git a/vendor/jfcherng/php-diff/.php-cs-fixer.dist.php b/vendor/jfcherng/php-diff/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..1878a60
--- /dev/null
+++ b/vendor/jfcherng/php-diff/.php-cs-fixer.dist.php
@@ -0,0 +1,78 @@
+<?php
+
+$config = (new PhpCsFixer\Config())
+ ->setIndent(" ")
+ ->setLineEnding("\n")
+ ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache')
+ ->setRiskyAllowed(true)
+ ->setRules([
+ '@PHP71Migration' => true,
+ '@PHP73Migration' => false,
+ '@PhpCsFixer' => true,
+ '@PhpCsFixer:risky' => true,
+ '@PSR12' => true,
+ '@Symfony' => true,
+ '@Symfony:risky' => true,
+ 'align_multiline_comment' => true,
+ 'array_indentation' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'combine_consecutive_issets' => true,
+ 'combine_consecutive_unsets' => true,
+ 'combine_nested_dirname' => true,
+ 'comment_to_phpdoc' => true,
+ 'compact_nullable_typehint' => true,
+ 'concat_space' => ['spacing' => 'one'],
+ 'escape_implicit_backslashes' => false,
+ 'fully_qualified_strict_types' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'list_syntax' => ['syntax' => 'short'],
+ 'method_argument_space' => ['ensure_fully_multiline' => true],
+ 'native_constant_invocation' => true,
+ 'native_function_invocation' => true,
+ 'native_function_type_declaration_casing' => true,
+ 'no_alternative_syntax' => true,
+ 'no_multiline_whitespace_before_semicolons' => true,
+ 'no_null_property_initialization' => true,
+ 'no_short_echo_tag' => true,
+ 'no_superfluous_elseif' => true,
+ 'no_trailing_whitespace_in_string' => false, // test cases have trailing spaces
+ 'no_unneeded_control_parentheses' => true,
+ 'no_useless_else' => true,
+ 'no_useless_return' => true,
+ 'not_operator_with_space' => false,
+ 'not_operator_with_successor_space' => false,
+ 'ordered_class_elements' => true,
+ 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['class', 'const', 'function']],
+ 'ordered_interfaces' => true,
+ 'php_unit_ordered_covers' => true,
+ 'php_unit_set_up_tear_down_visibility' => true,
+ 'php_unit_strict' => true,
+ 'php_unit_test_class_requires_covers' => true,
+ 'phpdoc_add_missing_param_annotation' => true,
+ 'phpdoc_order' => true,
+ 'phpdoc_to_comment' => false,
+ 'phpdoc_types_order' => true,
+ 'pow_to_exponentiation' => true,
+ 'random_api_migration' => true,
+ 'return_assignment' => false,
+ 'simple_to_complex_string_variable' => true,
+ 'single_line_comment_style' => true,
+ 'single_trait_insert_per_statement' => true,
+ 'strict_comparison' => false,
+ 'strict_param' => false,
+ 'string_line_ending' => true,
+ 'yoda_style' => false,
+ ])
+ ->setFinder(
+ PhpCsFixer\Finder::create()
+ ->notPath('/branch-\\w+/') // git worktree
+ ->exclude('libs')
+ ->exclude('tests/data')
+ ->exclude('tests/Fixtures')
+ ->exclude('var')
+ ->exclude('vendor')
+ ->in(__DIR__)
+ )
+;
+
+return $config;
diff --git a/vendor/jfcherng/php-diff/.phpstorm.meta.php b/vendor/jfcherng/php-diff/.phpstorm.meta.php
new file mode 100644
index 0000000..a8f8c52
--- /dev/null
+++ b/vendor/jfcherng/php-diff/.phpstorm.meta.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace PHPSTORM_META;
+
+override(
+ \Jfcherng\Diff\Factory\LineRendererFactory::getInstance(0),
+ map(['' => 'Jfcherng\Diff\Renderer\Html\LineRenderer\@'])
+);
+override(
+ \Jfcherng\Diff\Factory\LineRendererFactory::make(0),
+ map(['' => 'Jfcherng\Diff\Renderer\Html\LineRenderer\@'])
+);
+
+override(
+ \Jfcherng\Diff\Factory\RendererFactory::getInstance(0),
+ map([
+ // html
+ 'Combined' => \Jfcherng\Diff\Renderer\Html\Combined::class,
+ 'Inline' => \Jfcherng\Diff\Renderer\Html\Inline::class,
+ 'Json' => \Jfcherng\Diff\Renderer\Html\Json::class,
+ 'JsonHtml' => \Jfcherng\Diff\Renderer\Html\JsonHtml::class,
+ 'SideBySide' => \Jfcherng\Diff\Renderer\Html\SideBySide::class,
+ // text
+ 'Context' => \Jfcherng\Diff\Renderer\Text\Context::class,
+ 'JsonText' => \Jfcherng\Diff\Renderer\Text\JsonText::class,
+ 'Unified' => \Jfcherng\Diff\Renderer\Text\Unified::class,
+ ])
+);
+override(
+ \Jfcherng\Diff\Factory\RendererFactory::make(0),
+ map([
+ // html
+ 'Combined' => \Jfcherng\Diff\Renderer\Html\Combined::class,
+ 'Inline' => \Jfcherng\Diff\Renderer\Html\Inline::class,
+ 'Json' => \Jfcherng\Diff\Renderer\Html\Json::class,
+ 'JsonHtml' => \Jfcherng\Diff\Renderer\Html\JsonHtml::class,
+ 'SideBySide' => \Jfcherng\Diff\Renderer\Html\SideBySide::class,
+ // text
+ 'Context' => \Jfcherng\Diff\Renderer\Text\Context::class,
+ 'JsonText' => \Jfcherng\Diff\Renderer\Text\JsonText::class,
+ 'Unified' => \Jfcherng\Diff\Renderer\Text\Unified::class,
+ ])
+);
diff --git a/vendor/jfcherng/php-diff/LICENSE b/vendor/jfcherng/php-diff/LICENSE
new file mode 100644
index 0000000..52d05aa
--- /dev/null
+++ b/vendor/jfcherng/php-diff/LICENSE
@@ -0,0 +1,31 @@
+BSD 3-Clause License
+
+Copyright (c) 2018-2022 Jack Cherng <jfcherng@gmail.com>
+Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
+
+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 copyright holder 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 HOLDER OR 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.
diff --git a/vendor/jfcherng/php-diff/composer.json b/vendor/jfcherng/php-diff/composer.json
new file mode 100644
index 0000000..66533f3
--- /dev/null
+++ b/vendor/jfcherng/php-diff/composer.json
@@ -0,0 +1,69 @@
+{
+ "name": "jfcherng/php-diff",
+ "description": "A comprehensive library for generating differences between two strings in multiple formats (unified, side by side HTML etc).",
+ "type": "library",
+ "license": "BSD-3-Clause",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "minimum-stability": "beta",
+ "prefer-stable": true,
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Jfcherng\\Diff\\Test\\": "tests/"
+ }
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "jfcherng/php-color-output": "^2.0",
+ "jfcherng/php-mb-string": "^1.4.6",
+ "jfcherng/php-sequence-matcher": "^3.2.8"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.6"
+ },
+ "config": {
+ "platform": {
+ "php": "7.1.3"
+ },
+ "sort-packages": true
+ },
+ "scripts": {
+ "analyze": [
+ "phan --color",
+ "phpcs --colors -n"
+ ],
+ "fix": [
+ "php-cs-fixer fix --verbose"
+ ],
+ "server": [
+ "Composer\\Config::disableProcessTimeout",
+ "@php -S localhost:12388 -t example/"
+ ],
+ "test": [
+ "phpunit --verbose"
+ ]
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/DiffHelper.php b/vendor/jfcherng/php-diff/src/DiffHelper.php
new file mode 100644
index 0000000..7c7165f
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/DiffHelper.php
@@ -0,0 +1,184 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff;
+
+use Jfcherng\Diff\Factory\RendererFactory;
+use Jfcherng\Diff\Renderer\RendererConstant;
+
+final class DiffHelper
+{
+ /**
+ * The constructor.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Get the absolute path of the project root directory.
+ */
+ public static function getProjectDirectory(): string
+ {
+ static $path;
+
+ return $path = $path ?? \realpath(__DIR__ . '/..');
+ }
+
+ /**
+ * Get the information about available renderers.
+ */
+ public static function getRenderersInfo(): array
+ {
+ static $info;
+
+ if (isset($info)) {
+ return $info;
+ }
+
+ $glob = \implode(\DIRECTORY_SEPARATOR, [
+ static::getProjectDirectory(),
+ 'src',
+ 'Renderer',
+ '{' . \implode(',', RendererConstant::RENDERER_TYPES) . '}',
+ '*.php',
+ ]);
+
+ $fileNames = \array_map(
+ // get basename without file extension
+ function (string $file): string {
+ return \pathinfo($file, \PATHINFO_FILENAME);
+ },
+ // paths of all Renderer files
+ \glob($glob, \GLOB_BRACE)
+ );
+
+ $renderers = \array_filter(
+ $fileNames,
+ // only normal class files are wanted
+ function (string $fileName): bool {
+ return
+ \substr($fileName, 0, 8) !== 'Abstract'
+ && \substr($fileName, -9) !== 'Interface'
+ && \substr($fileName, -5) !== 'Trait';
+ }
+ );
+
+ $info = [];
+ foreach ($renderers as $renderer) {
+ $info[$renderer] = RendererFactory::resolveRenderer($renderer)::INFO;
+ }
+
+ return $info;
+ }
+
+ /**
+ * Get the available renderers.
+ *
+ * @return string[] the available renderers
+ */
+ public static function getAvailableRenderers(): array
+ {
+ return \array_keys(self::getRenderersInfo());
+ }
+
+ /**
+ * Get the content of the CSS style sheet for HTML renderers.
+ *
+ * @throws \LogicException path is a directory
+ * @throws \RuntimeException path cannot be opened
+ */
+ public static function getStyleSheet(): string
+ {
+ static $fileContent;
+
+ if (isset($fileContent)) {
+ return $fileContent;
+ }
+
+ $filePath = static::getProjectDirectory() . '/example/diff-table.css';
+
+ $file = new \SplFileObject($filePath, 'r');
+
+ return $fileContent = $file->fread($file->getSize());
+ }
+
+ /**
+ * Gets the diff statistics such as inserted and deleted etc...
+ *
+ * @return array<string,float> the statistics
+ */
+ public static function getStatistics(): array
+ {
+ return Differ::getInstance()->getStatistics();
+ }
+
+ /**
+ * All-in-one static method to calculate the diff between two strings (or arrays of strings).
+ *
+ * @param string|string[] $old the old string (or array of lines)
+ * @param string|string[] $new the new string (or array of lines)
+ * @param string $renderer the renderer name
+ * @param array $differOptions the options for Differ object
+ * @param array $rendererOptions the options for renderer object
+ *
+ * @return string the rendered differences
+ */
+ public static function calculate(
+ $old,
+ $new,
+ string $renderer = 'Unified',
+ array $differOptions = [],
+ array $rendererOptions = []
+ ): string {
+ // always convert into array form
+ \is_string($old) && ($old = \explode("\n", $old));
+ \is_string($new) && ($new = \explode("\n", $new));
+
+ return RendererFactory::getInstance($renderer)
+ ->setOptions($rendererOptions)
+ ->render(
+ Differ::getInstance()
+ ->setOldNew($old, $new)
+ ->setOptions($differOptions)
+ );
+ }
+
+ /**
+ * All-in-one static method to calculate the diff between two files.
+ *
+ * @param string $old the path of the old file
+ * @param string $new the path of the new file
+ * @param string $renderer the renderer name
+ * @param array $differOptions the options for Differ object
+ * @param array $rendererOptions the options for renderer object
+ *
+ * @throws \LogicException path is a directory
+ * @throws \RuntimeException path cannot be opened
+ *
+ * @return string the rendered differences
+ */
+ public static function calculateFiles(
+ string $old,
+ string $new,
+ string $renderer = 'Unified',
+ array $differOptions = [],
+ array $rendererOptions = []
+ ): string {
+ // we want to leave the line-ending problem to static::calculate()
+ // so do not set SplFileObject::DROP_NEW_LINE flag
+ // otherwise, we will lose \r if the line-ending is \r\n
+ $oldFile = new \SplFileObject($old, 'r');
+ $newFile = new \SplFileObject($new, 'r');
+
+ return static::calculate(
+ // fread() requires the length > 0 hence we plus 1 for empty files
+ $oldFile->fread($oldFile->getSize() + 1),
+ $newFile->fread($newFile->getSize() + 1),
+ $renderer,
+ $differOptions,
+ $rendererOptions
+ );
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Differ.php b/vendor/jfcherng/php-diff/src/Differ.php
new file mode 100644
index 0000000..bcb29ab
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Differ.php
@@ -0,0 +1,502 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff;
+
+use Jfcherng\Diff\Utility\Arr;
+
+/**
+ * A comprehensive library for generating differences between two strings
+ * in multiple formats (unified, side by side HTML etc).
+ *
+ * @author Jack Cherng <jfcherng@gmail.com>
+ * @author Chris Boulton <chris.boulton@interspire.com>
+ *
+ * @see http://github.com/chrisboulton/php-diff
+ */
+final class Differ
+{
+ /**
+ * @var int a safe number for indicating showing all contexts
+ */
+ public const CONTEXT_ALL = \PHP_INT_MAX >> 3;
+
+ /**
+ * @var string used to indicate a line has no EOL
+ *
+ * Arbitrary chars from the 15-16th Unicode reserved areas
+ * and hopefully, they won't appear in source texts
+ */
+ public const LINE_NO_EOL = "\u{fcf28}\u{fc231}";
+
+ /**
+ * @var array cached properties and their default values
+ */
+ private const CACHED_PROPERTIES = [
+ 'groupedOpcodes' => [],
+ 'groupedOpcodesGnu' => [],
+ 'oldNoEolAtEofIdx' => -1,
+ 'newNoEolAtEofIdx' => -1,
+ 'oldNewComparison' => 0,
+ ];
+
+ /**
+ * @var array array of the options that have been applied for generating the diff
+ */
+ public $options = [];
+
+ /**
+ * @var string[] the old sequence
+ */
+ private $old = [];
+
+ /**
+ * @var string[] the new sequence
+ */
+ private $new = [];
+
+ /**
+ * @var bool is any of cached properties dirty?
+ */
+ private $isCacheDirty = true;
+
+ /**
+ * @var SequenceMatcher the sequence matcher
+ */
+ private $sequenceMatcher;
+
+ /**
+ * @var int
+ */
+ private $oldSrcLength = 0;
+
+ /**
+ * @var int
+ */
+ private $newSrcLength = 0;
+
+ /**
+ * @var int the end index for the old if the old has no EOL at EOF
+ * -1 means the old has an EOL at EOF
+ */
+ private $oldNoEolAtEofIdx = -1;
+
+ /**
+ * @var int the end index for the new if the new has no EOL at EOF
+ * -1 means the new has an EOL at EOF
+ */
+ private $newNoEolAtEofIdx = -1;
+
+ /**
+ * @var int the result of comparing the old and the new with the spaceship operator
+ * -1 means old < new, 0 means old == new, 1 means old > new
+ */
+ private $oldNewComparison = 0;
+
+ /**
+ * @var int[][][] array containing the generated opcodes for the differences between the two items
+ */
+ private $groupedOpcodes = [];
+
+ /**
+ * @var int[][][] array containing the generated opcodes for the differences between the two items (GNU version)
+ */
+ private $groupedOpcodesGnu = [];
+
+ /**
+ * @var array associative array of the default options available for the Differ class and their default value
+ */
+ private static $defaultOptions = [
+ // show how many neighbor lines
+ // Differ::CONTEXT_ALL can be used to show the whole file
+ 'context' => 3,
+ // ignore case difference
+ 'ignoreWhitespace' => false,
+ // ignore whitespace difference
+ 'ignoreCase' => false,
+ ];
+
+ /**
+ * The constructor.
+ *
+ * @param string[] $old array containing the lines of the old string to compare
+ * @param string[] $new array containing the lines for the new string to compare
+ * @param array $options the options
+ */
+ public function __construct(array $old, array $new, array $options = [])
+ {
+ $this->sequenceMatcher = new SequenceMatcher([], []);
+
+ $this->setOldNew($old, $new)->setOptions($options);
+ }
+
+ /**
+ * Set old and new.
+ *
+ * @param string[] $old the old
+ * @param string[] $new the new
+ */
+ public function setOldNew(array $old, array $new): self
+ {
+ return $this->setOld($old)->setNew($new);
+ }
+
+ /**
+ * Set old.
+ *
+ * @param string[] $old the old
+ */
+ public function setOld(array $old): self
+ {
+ if ($this->old !== $old) {
+ $this->old = $old;
+ $this->isCacheDirty = true;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set new.
+ *
+ * @param string[] $new the new
+ */
+ public function setNew(array $new): self
+ {
+ if ($this->new !== $new) {
+ $this->new = $new;
+ $this->isCacheDirty = true;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the options.
+ *
+ * @param array $options the options
+ */
+ public function setOptions(array $options): self
+ {
+ $mergedOptions = $options + static::$defaultOptions;
+
+ if ($this->options !== $mergedOptions) {
+ $this->options = $mergedOptions;
+ $this->isCacheDirty = true;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get a range of lines from $start to $end from the old.
+ *
+ * @param int $start the starting index (negative = count from backward)
+ * @param null|int $end the ending index (negative = count from backward)
+ * if is null, it returns a slice from $start to the end
+ *
+ * @return string[] array of all of the lines between the specified range
+ */
+ public function getOld(int $start = 0, ?int $end = null): array
+ {
+ return Arr::getPartialByIndex($this->old, $start, $end);
+ }
+
+ /**
+ * Get a range of lines from $start to $end from the new.
+ *
+ * @param int $start the starting index (negative = count from backward)
+ * @param null|int $end the ending index (negative = count from backward)
+ * if is null, it returns a slice from $start to the end
+ *
+ * @return string[] array of all of the lines between the specified range
+ */
+ public function getNew(int $start = 0, ?int $end = null): array
+ {
+ return Arr::getPartialByIndex($this->new, $start, $end);
+ }
+
+ /**
+ * Get the options.
+ *
+ * @return array the options
+ */
+ public function getOptions(): array
+ {
+ return $this->options;
+ }
+
+ /**
+ * Get the old no EOL at EOF index.
+ *
+ * @return int the old no EOL at EOF index
+ */
+ public function getOldNoEolAtEofIdx(): int
+ {
+ return $this->finalize()->oldNoEolAtEofIdx;
+ }
+
+ /**
+ * Get the new no EOL at EOF index.
+ *
+ * @return int the new no EOL at EOF index
+ */
+ public function getNewNoEolAtEofIdx(): int
+ {
+ return $this->finalize()->newNoEolAtEofIdx;
+ }
+
+ /**
+ * Compare the old and the new with the spaceship operator.
+ */
+ public function getOldNewComparison(): int
+ {
+ return $this->finalize()->oldNewComparison;
+ }
+
+ /**
+ * Get the singleton.
+ */
+ public static function getInstance(): self
+ {
+ static $singleton;
+
+ return $singleton = $singleton ?? new static([], []);
+ }
+
+ /**
+ * Gets the diff statistics such as inserted and deleted etc...
+ *
+ * @return array<string,float> the statistics
+ */
+ public function getStatistics(): array
+ {
+ $ret = [
+ 'inserted' => 0,
+ 'deleted' => 0,
+ 'unmodified' => 0,
+ 'changedRatio' => 0.0,
+ ];
+
+ foreach ($this->getGroupedOpcodes() as $hunk) {
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ if ($op & (SequenceMatcher::OP_INS | SequenceMatcher::OP_REP)) {
+ $ret['inserted'] += $j2 - $j1;
+ }
+ if ($op & (SequenceMatcher::OP_DEL | SequenceMatcher::OP_REP)) {
+ $ret['deleted'] += $i2 - $i1;
+ }
+ }
+ }
+
+ $ret['unmodified'] = $this->oldSrcLength - $ret['deleted'];
+ $ret['changedRatio'] = 1 - ($ret['unmodified'] / $this->oldSrcLength);
+
+ return $ret;
+ }
+
+ /**
+ * Generate a list of the compiled and grouped opcodes for the differences between the
+ * two strings. Generally called by the renderer, this class instantiates the sequence
+ * matcher and performs the actual diff generation and return an array of the opcodes
+ * for it. Once generated, the results are cached in the Differ class instance.
+ *
+ * @return int[][][] array of the grouped opcodes for the generated diff
+ */
+ public function getGroupedOpcodes(): array
+ {
+ $this->finalize();
+
+ if (!empty($this->groupedOpcodes)) {
+ return $this->groupedOpcodes;
+ }
+
+ $old = $this->old;
+ $new = $this->new;
+ $this->getGroupedOpcodesPre($old, $new);
+
+ $opcodes = $this->sequenceMatcher
+ ->setSequences($old, $new)
+ ->getGroupedOpcodes($this->options['context']);
+
+ $this->getGroupedOpcodesPost($opcodes);
+
+ return $this->groupedOpcodes = $opcodes;
+ }
+
+ /**
+ * A EOL-at-EOF-sensitive version of getGroupedOpcodes().
+ *
+ * @return int[][][] array of the grouped opcodes for the generated diff (GNU version)
+ */
+ public function getGroupedOpcodesGnu(): array
+ {
+ $this->finalize();
+
+ if (!empty($this->groupedOpcodesGnu)) {
+ return $this->groupedOpcodesGnu;
+ }
+
+ $old = $this->old;
+ $new = $this->new;
+ $this->getGroupedOpcodesGnuPre($old, $new);
+
+ $opcodes = $this->sequenceMatcher
+ ->setSequences($old, $new)
+ ->getGroupedOpcodes($this->options['context']);
+
+ $this->getGroupedOpcodesGnuPost($opcodes);
+
+ return $this->groupedOpcodesGnu = $opcodes;
+ }
+
+ /**
+ * Triggered before getGroupedOpcodes(). May modify the $old and $new.
+ *
+ * @param string[] $old the old
+ * @param string[] $new the new
+ */
+ private function getGroupedOpcodesPre(array &$old, array &$new): void
+ {
+ // append these lines to make sure the last block of the diff result is OP_EQ
+ static $eolAtEofHelperLines = [
+ SequenceMatcher::APPENDED_HELPER_LINE,
+ SequenceMatcher::APPENDED_HELPER_LINE,
+ SequenceMatcher::APPENDED_HELPER_LINE,
+ SequenceMatcher::APPENDED_HELPER_LINE,
+ ];
+
+ $this->oldSrcLength = \count($old);
+ \array_push($old, ...$eolAtEofHelperLines);
+
+ $this->newSrcLength = \count($new);
+ \array_push($new, ...$eolAtEofHelperLines);
+ }
+
+ /**
+ * Triggered after getGroupedOpcodes(). May modify the $opcodes.
+ *
+ * @param int[][][] $opcodes the opcodes
+ */
+ private function getGroupedOpcodesPost(array &$opcodes): void
+ {
+ // remove those extra lines cause by adding extra SequenceMatcher::APPENDED_HELPER_LINE lines
+ foreach ($opcodes as $hunkIdx => &$hunk) {
+ foreach ($hunk as $blockIdx => &$block) {
+ // range overflow
+ if ($block[1] > $this->oldSrcLength) {
+ $block[1] = $this->oldSrcLength;
+ }
+ if ($block[2] > $this->oldSrcLength) {
+ $block[2] = $this->oldSrcLength;
+ }
+ if ($block[3] > $this->newSrcLength) {
+ $block[3] = $this->newSrcLength;
+ }
+ if ($block[4] > $this->newSrcLength) {
+ $block[4] = $this->newSrcLength;
+ }
+
+ // useless extra block?
+ /** @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset */
+ if ($block[1] === $block[2] && $block[3] === $block[4]) {
+ unset($hunk[$blockIdx]);
+ }
+ }
+
+ if (empty($hunk)) {
+ unset($opcodes[$hunkIdx]);
+ }
+ }
+ }
+
+ /**
+ * Triggered before getGroupedOpcodesGnu(). May modify the $old and $new.
+ *
+ * @param string[] $old the old
+ * @param string[] $new the new
+ */
+ private function getGroupedOpcodesGnuPre(array &$old, array &$new): void
+ {
+ /**
+ * Make the lines to be prepared for GNU-style diff.
+ *
+ * This method checks whether $lines has no EOL at EOF and append a special
+ * indicator to the last line.
+ *
+ * @param string[] $lines the lines created by simply explode("\n", $string)
+ */
+ $createGnuCompatibleLines = static function (array $lines): array {
+ // note that the $lines should not be empty at this point
+ // they have at least one element "" in the array because explode("\n", "") === [""]
+ $lastLineIdx = \count($lines) - 1;
+ $lastLine = &$lines[$lastLineIdx];
+
+ if ($lastLine === '') {
+ // remove the last plain "" line since we don't need it anymore
+ // use array_slice() to also reset the array index
+ $lines = \array_slice($lines, 0, -1);
+ } else {
+ // this means the original source has no EOL at EOF
+ // we append a special indicator to that line so it no longer matches
+ $lastLine .= self::LINE_NO_EOL;
+ }
+
+ return $lines;
+ };
+
+ $old = $createGnuCompatibleLines($old);
+ $new = $createGnuCompatibleLines($new);
+
+ $this->getGroupedOpcodesPre($old, $new);
+ }
+
+ /**
+ * Triggered after getGroupedOpcodesGnu(). May modify the $opcodes.
+ *
+ * @param int[][][] $opcodes the opcodes
+ */
+ private function getGroupedOpcodesGnuPost(array &$opcodes): void
+ {
+ $this->getGroupedOpcodesPost($opcodes);
+ }
+
+ /**
+ * Claim this class has settled down and we could calculate cached
+ * properties by current properties.
+ *
+ * This method must be called before accessing cached properties to
+ * make suer that you will not get a outdated cached value.
+ *
+ * @internal
+ */
+ private function finalize(): self
+ {
+ if ($this->isCacheDirty) {
+ $this->resetCachedResults();
+
+ $this->oldNoEolAtEofIdx = $this->getOld(-1) === [''] ? -1 : \count($this->old);
+ $this->newNoEolAtEofIdx = $this->getNew(-1) === [''] ? -1 : \count($this->new);
+ $this->oldNewComparison = $this->old <=> $this->new;
+
+ $this->sequenceMatcher->setOptions($this->options);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Reset cached results.
+ */
+ private function resetCachedResults(): self
+ {
+ foreach (static::CACHED_PROPERTIES as $property => $value) {
+ $this->{$property} = $value;
+ }
+
+ $this->isCacheDirty = false;
+
+ return $this;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Exception/FileNotFoundException.php b/vendor/jfcherng/php-diff/src/Exception/FileNotFoundException.php
new file mode 100644
index 0000000..9a9ed8f
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Exception/FileNotFoundException.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Exception;
+
+final class FileNotFoundException extends \Exception
+{
+ public function __construct(string $filepath = '', int $code = 0, \Throwable $previous = null)
+ {
+ parent::__construct("File not found: {$filepath}", $code, $previous);
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Exception/UnsupportedFunctionException.php b/vendor/jfcherng/php-diff/src/Exception/UnsupportedFunctionException.php
new file mode 100644
index 0000000..e2d4fed
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Exception/UnsupportedFunctionException.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Exception;
+
+final class UnsupportedFunctionException extends \Exception
+{
+ public function __construct(string $funcName = '', int $code = 0, \Throwable $previous = null)
+ {
+ parent::__construct("Unsupported function: {$funcName}", $code, $previous);
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Factory/LineRendererFactory.php b/vendor/jfcherng/php-diff/src/Factory/LineRendererFactory.php
new file mode 100644
index 0000000..de7438c
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Factory/LineRendererFactory.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Factory;
+
+use Jfcherng\Diff\Renderer\Html\LineRenderer\AbstractLineRenderer;
+use Jfcherng\Diff\Renderer\RendererConstant;
+
+final class LineRendererFactory
+{
+ /**
+ * Instances of line renderers.
+ *
+ * @var AbstractLineRenderer[]
+ */
+ private static $singletons = [];
+
+ /**
+ * The constructor.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Get the singleton of a line renderer.
+ *
+ * @param string $type the type
+ * @param mixed ...$ctorArgs the constructor arguments
+ */
+ public static function getInstance(string $type, ...$ctorArgs): AbstractLineRenderer
+ {
+ if (!isset(self::$singletons[$type])) {
+ self::$singletons[$type] = self::make($type, ...$ctorArgs);
+ }
+
+ return self::$singletons[$type];
+ }
+
+ /**
+ * Make a new instance of a line renderer.
+ *
+ * @param string $type the type
+ * @param mixed ...$ctorArgs the constructor arguments
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function make(string $type, ...$ctorArgs): AbstractLineRenderer
+ {
+ $className = RendererConstant::RENDERER_NAMESPACE . '\\Html\\LineRenderer\\' . \ucfirst($type);
+
+ if (!\class_exists($className)) {
+ throw new \InvalidArgumentException("LineRenderer not found: {$type}");
+ }
+
+ return new $className(...$ctorArgs);
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Factory/RendererFactory.php b/vendor/jfcherng/php-diff/src/Factory/RendererFactory.php
new file mode 100644
index 0000000..7f1b1d1
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Factory/RendererFactory.php
@@ -0,0 +1,83 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Factory;
+
+use Jfcherng\Diff\Renderer\AbstractRenderer;
+use Jfcherng\Diff\Renderer\RendererConstant;
+
+final class RendererFactory
+{
+ /**
+ * Instances of renderers.
+ *
+ * @var AbstractRenderer[]
+ */
+ private static $singletons = [];
+
+ /**
+ * The constructor.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Get the singleton of a renderer.
+ *
+ * @param string $renderer the renderer
+ * @param mixed ...$ctorArgs the constructor arguments
+ */
+ public static function getInstance(string $renderer, ...$ctorArgs): AbstractRenderer
+ {
+ if (!isset(self::$singletons[$renderer])) {
+ self::$singletons[$renderer] = self::make($renderer, ...$ctorArgs);
+ }
+
+ return self::$singletons[$renderer];
+ }
+
+ /**
+ * Make a new instance of a renderer.
+ *
+ * @param string $renderer the renderer
+ * @param mixed ...$ctorArgs the constructor arguments
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function make(string $renderer, ...$ctorArgs): AbstractRenderer
+ {
+ $className = self::resolveRenderer($renderer);
+
+ if (!isset($className)) {
+ throw new \InvalidArgumentException("Renderer not found: {$renderer}");
+ }
+
+ return new $className(...$ctorArgs);
+ }
+
+ /**
+ * Resolve the renderer name into a FQCN.
+ *
+ * @param string $renderer the renderer
+ */
+ public static function resolveRenderer(string $renderer): ?string
+ {
+ static $cache = [];
+
+ if (isset($cache[$renderer])) {
+ return $cache[$renderer];
+ }
+
+ foreach (RendererConstant::RENDERER_TYPES as $type) {
+ $className = RendererConstant::RENDERER_NAMESPACE . "\\{$type}\\{$renderer}";
+
+ if (\class_exists($className)) {
+ return $cache[$renderer] = $className;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/AbstractRenderer.php b/vendor/jfcherng/php-diff/src/Renderer/AbstractRenderer.php
new file mode 100644
index 0000000..77477c8
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/AbstractRenderer.php
@@ -0,0 +1,230 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\SequenceMatcher;
+use Jfcherng\Diff\Utility\Language;
+
+/**
+ * Base class for diff renderers.
+ */
+abstract class AbstractRenderer implements RendererInterface
+{
+ /**
+ * @var array information about this renderer
+ */
+ public const INFO = [
+ 'desc' => 'default_desc',
+ 'type' => 'default_type',
+ ];
+
+ /**
+ * @var bool Is this renderer pure text?
+ */
+ public const IS_TEXT_RENDERER = true;
+
+ /**
+ * @var string[] array of the opcodes and their corresponding symbols
+ */
+ public const SYMBOL_MAP = [
+ SequenceMatcher::OP_DEL => '-',
+ SequenceMatcher::OP_EQ => ' ',
+ SequenceMatcher::OP_INS => '+',
+ SequenceMatcher::OP_REP => '!',
+ ];
+
+ /**
+ * @var Language the language translation object
+ */
+ protected $t;
+
+ /**
+ * @var array array of the default options that apply to this renderer
+ */
+ protected static $defaultOptions = [
+ // how detailed the rendered HTML in-line diff is? (none, line, word, char)
+ 'detailLevel' => 'line',
+ // renderer language: eng, cht, chs, jpn, ...
+ // or an array which has the same keys with a language file
+ 'language' => 'eng',
+ // show line numbers in HTML renderers
+ 'lineNumbers' => true,
+ // show a separator between different diff hunks in HTML renderers
+ 'separateBlock' => true,
+ // show the (table) header
+ 'showHeader' => true,
+ // the frontend HTML could use CSS "white-space: pre;" to visualize consecutive whitespaces
+ // but if you want to visualize them in the backend with "&nbsp;", you can set this to true
+ 'spacesToNbsp' => false,
+ // HTML renderer tab width (negative = do not convert into spaces)
+ 'tabSize' => 4,
+ // this option is currently only for the Combined renderer.
+ // it determines whether a replace-type block should be merged or not
+ // depending on the content changed ratio, which values between 0 and 1.
+ 'mergeThreshold' => 0.8,
+ // this option is currently only for the Unified and the Context renderers.
+ // RendererConstant::CLI_COLOR_AUTO = colorize the output if possible (default)
+ // RendererConstant::CLI_COLOR_ENABLE = force to colorize the output
+ // RendererConstant::CLI_COLOR_DISABLE = force not to colorize the output
+ 'cliColorization' => RendererConstant::CLI_COLOR_AUTO,
+ // this option is currently only for the Json renderer.
+ // internally, ops (tags) are all int type but this is not good for human reading.
+ // set this to "true" to convert them into string form before outputting.
+ 'outputTagAsString' => false,
+ // this option is currently only for the Json renderer.
+ // it controls how the output JSON is formatted.
+ // see availabe options on https://www.php.net/manual/en/function.json-encode.php
+ 'jsonEncodeFlags' => \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE,
+ // this option is currently effective when the "detailLevel" is "word"
+ // characters listed in this array can be used to make diff segments into a whole
+ // for example, making "<del>good</del>-<del>looking</del>" into "<del>good-looking</del>"
+ // this should bring better readability but set this to empty array if you do not want it
+ 'wordGlues' => ['-', ' '],
+ // change this value to a string as the returned diff if the two input strings are identical
+ 'resultForIdenticals' => null,
+ // extra HTML classes added to the DOM of the diff container
+ 'wrapperClasses' => ['diff-wrapper'],
+ ];
+
+ /**
+ * @var array array containing the user applied and merged default options for the renderer
+ */
+ protected $options = [];
+
+ /**
+ * The constructor. Instantiates the rendering engine and if options are passed,
+ * sets the options for the renderer.
+ *
+ * @param array $options optionally, an array of the options for the renderer
+ */
+ public function __construct(array $options = [])
+ {
+ $this->setOptions($options);
+ }
+
+ /**
+ * Set the options of the renderer to those supplied in the passed in array.
+ * Options are merged with the default to ensure that there aren't any missing
+ * options.
+ *
+ * @param array $options the options
+ *
+ * @return static
+ */
+ public function setOptions(array $options): self
+ {
+ $newOptions = $options + static::$defaultOptions;
+
+ $this->updateLanguage(
+ $this->options['language'] ?? '',
+ $newOptions['language']
+ );
+
+ $this->options = $newOptions;
+
+ return $this;
+ }
+
+ /**
+ * Get the options.
+ *
+ * @return array the options
+ */
+ public function getOptions(): array
+ {
+ return $this->options;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @final
+ *
+ * @todo mark this method with "final" in the next major release
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function getResultForIdenticals(): string
+ {
+ $custom = $this->options['resultForIdenticals'];
+
+ if (isset($custom) && !\is_string($custom)) {
+ throw new \InvalidArgumentException('renderer option `resultForIdenticals` must be null or string.');
+ }
+
+ return $custom ?? $this->getResultForIdenticalsDefault();
+ }
+
+ /**
+ * Get the renderer default result when the old and the new are the same.
+ */
+ abstract public function getResultForIdenticalsDefault(): string;
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function render(Differ $differ): string
+ {
+ // the "no difference" situation may happen frequently
+ return $differ->getOldNewComparison() === 0
+ ? $this->getResultForIdenticals()
+ : $this->renderWorker($differ);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function renderArray(array $differArray): string
+ {
+ return $this->renderArrayWorker($differArray);
+ }
+
+ /**
+ * The real worker for self::render().
+ *
+ * @param Differ $differ the differ object
+ */
+ abstract protected function renderWorker(Differ $differ): string;
+
+ /**
+ * The real worker for self::renderArray().
+ *
+ * @param array[][] $differArray the differ array
+ */
+ abstract protected function renderArrayWorker(array $differArray): string;
+
+ /**
+ * Update the Language object.
+ *
+ * @param string|string[] $old the old language
+ * @param string|string[] $new the new language
+ *
+ * @return static
+ */
+ protected function updateLanguage($old, $new): self
+ {
+ if (!isset($this->t) || $old !== $new) {
+ $this->t = new Language($new);
+ }
+
+ return $this;
+ }
+
+ /**
+ * A shorthand to do translation.
+ *
+ * @param string $text The text
+ * @param bool $escapeHtml Escape the translated text for HTML?
+ *
+ * @return string the translated text
+ */
+ protected function _(string $text, bool $escapeHtml = true): string
+ {
+ $text = $this->t->translate($text);
+
+ return $escapeHtml ? \htmlspecialchars($text) : $text;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/AbstractHtml.php b/vendor/jfcherng/php-diff/src/Renderer/Html/AbstractHtml.php
new file mode 100644
index 0000000..49d8b4d
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/AbstractHtml.php
@@ -0,0 +1,365 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\Factory\LineRendererFactory;
+use Jfcherng\Diff\Renderer\AbstractRenderer;
+use Jfcherng\Diff\Renderer\Html\LineRenderer\AbstractLineRenderer;
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Diff\SequenceMatcher;
+use Jfcherng\Utility\MbString;
+
+/**
+ * Base renderer for rendering HTML-based diffs.
+ */
+abstract class AbstractHtml extends AbstractRenderer
+{
+ /**
+ * @var bool is this renderer pure text?
+ */
+ public const IS_TEXT_RENDERER = false;
+
+ /**
+ * @var string[] array of the different opcodes and how they are mapped to HTML classes
+ *
+ * @todo rename to OP_CLASS_MAP in v7
+ */
+ public const TAG_CLASS_MAP = [
+ SequenceMatcher::OP_DEL => 'del',
+ SequenceMatcher::OP_EQ => 'eq',
+ SequenceMatcher::OP_INS => 'ins',
+ SequenceMatcher::OP_REP => 'rep',
+ ];
+
+ /**
+ * Auto format the content in "changes" to be suitable for HTML output.
+ *
+ * This may not be a wanted behavior for some (custom) renderers
+ * if they want to do this by themselves in a later stage.
+ *
+ * @var bool
+ */
+ public const AUTO_FORMAT_CHANGES = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResultForIdenticalsDefault(): string
+ {
+ return '';
+ }
+
+ /**
+ * Render and return an array structure suitable for generating HTML
+ * based differences. Generally called by subclasses that generate a
+ * HTML based diff and return an array of the changes to show in the diff.
+ *
+ * @param Differ $differ the differ object
+ *
+ * @return array[][] generated changes, suitable for presentation in HTML
+ */
+ public function getChanges(Differ $differ): array
+ {
+ $lineRenderer = LineRendererFactory::make(
+ $this->options['detailLevel'],
+ $differ->getOptions(),
+ $this->options
+ );
+
+ $old = $differ->getOld();
+ $new = $differ->getNew();
+
+ $changes = [];
+
+ foreach ($differ->getGroupedOpcodes() as $hunk) {
+ $change = [];
+
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ $change[] = $this->getDefaultBlock($op, $i1, $j1);
+ $block = &$change[\count($change) - 1];
+
+ // if there are same amount of lines replaced
+ // we can render the inner detailed changes with corresponding lines
+ // @todo or use LineRenderer to do the job regardless different line counts?
+ if ($op === SequenceMatcher::OP_REP && $i2 - $i1 === $j2 - $j1) {
+ for ($k = $i2 - $i1 - 1; $k >= 0; --$k) {
+ $this->renderChangedExtent($lineRenderer, $old[$i1 + $k], $new[$j1 + $k]);
+ }
+ }
+
+ $block['old']['lines'] = \array_slice($old, $i1, $i2 - $i1);
+ $block['new']['lines'] = \array_slice($new, $j1, $j2 - $j1);
+ }
+ unset($block);
+
+ $changes[] = $change;
+ }
+
+ if (static::AUTO_FORMAT_CHANGES) {
+ $this->formatChanges($changes);
+ }
+
+ return $changes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderWorker(Differ $differ): string
+ {
+ $rendered = $this->redererChanges($this->getChanges($differ));
+
+ return $this->cleanUpDummyHtmlClosures($rendered);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderArrayWorker(array $differArray): string
+ {
+ $this->ensureChangesUseIntTag($differArray);
+
+ $rendered = $this->redererChanges($differArray);
+
+ return $this->cleanUpDummyHtmlClosures($rendered);
+ }
+
+ /**
+ * Render the array of changes.
+ *
+ * @param array[][] $changes the changes
+ *
+ * @todo rename typo to renderChanges() in v7
+ */
+ abstract protected function redererChanges(array $changes): string;
+
+ /**
+ * Renderer the changed extent.
+ *
+ * @param AbstractLineRenderer $lineRenderer the line renderer
+ * @param string $old the old line
+ * @param string $new the new line
+ */
+ protected function renderChangedExtent(AbstractLineRenderer $lineRenderer, string &$old, string &$new): void
+ {
+ static $mbOld, $mbNew;
+
+ $mbOld = $mbOld ?? new MbString();
+ $mbNew = $mbNew ?? new MbString();
+
+ $mbOld->set($old);
+ $mbNew->set($new);
+
+ $lineRenderer->render($mbOld, $mbNew);
+
+ $old = $mbOld->get();
+ $new = $mbNew->get();
+ }
+
+ /**
+ * Get the default block.
+ *
+ * @param int $op the operation
+ * @param int $i1 begin index of the diff of the old array
+ * @param int $j1 begin index of the diff of the new array
+ *
+ * @return array the default block
+ *
+ * @todo rename tag to op in v7
+ */
+ protected function getDefaultBlock(int $op, int $i1, int $j1): array
+ {
+ return [
+ 'tag' => $op,
+ 'old' => [
+ 'offset' => $i1,
+ 'lines' => [],
+ ],
+ 'new' => [
+ 'offset' => $j1,
+ 'lines' => [],
+ ],
+ ];
+ }
+
+ /**
+ * Make the content in "changes" suitable for HTML output.
+ *
+ * @param array[][] $changes the changes
+ */
+ final protected function formatChanges(array &$changes): void
+ {
+ foreach ($changes as &$hunk) {
+ foreach ($hunk as &$block) {
+ $block['old']['lines'] = $this->formatLines($block['old']['lines']);
+ $block['new']['lines'] = $this->formatLines($block['new']['lines']);
+
+ /** @phan-suppress-next-line PhanTypeInvalidLeftOperandOfBitwiseOp */
+ if ($block['tag'] & (SequenceMatcher::OP_REP | SequenceMatcher::OP_DEL)) {
+ $block['old']['lines'] = \str_replace(
+ RendererConstant::HTML_CLOSURES,
+ RendererConstant::HTML_CLOSURES_DEL,
+ $block['old']['lines']
+ );
+ }
+
+ /** @phan-suppress-next-line PhanTypeInvalidLeftOperandOfBitwiseOp */
+ if ($block['tag'] & (SequenceMatcher::OP_REP | SequenceMatcher::OP_INS)) {
+ $block['new']['lines'] = \str_replace(
+ RendererConstant::HTML_CLOSURES,
+ RendererConstant::HTML_CLOSURES_INS,
+ $block['new']['lines']
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Make a series of lines suitable for outputting in a HTML rendered diff.
+ *
+ * @param string[] $lines array of lines to format
+ *
+ * @return string[] array of the formatted lines
+ */
+ protected function formatLines(array $lines): array
+ {
+ /**
+ * To prevent from invoking the same function calls for several times,
+ * we can glue lines into a string and call functions for one time.
+ * After that, we split the string back into lines.
+ */
+ return \explode(
+ RendererConstant::IMPLODE_DELIMITER,
+ $this->formatStringFromLines(
+ \implode(
+ RendererConstant::IMPLODE_DELIMITER,
+ $lines
+ )
+ )
+ );
+ }
+
+ /**
+ * Make a string suitable for outputting in a HTML rendered diff.
+ *
+ * This my involve replacing tab characters with spaces, making the HTML safe
+ * for output, ensuring that double spaces are replaced with &nbsp; etc.
+ *
+ * @param string $string the string of imploded lines
+ *
+ * @return string the formatted string
+ */
+ protected function formatStringFromLines(string $string): string
+ {
+ $string = $this->expandTabs($string, $this->options['tabSize']);
+ $string = $this->htmlSafe($string);
+
+ if ($this->options['spacesToNbsp']) {
+ $string = $this->htmlFixSpaces($string);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Replace tabs in a string with a number of spaces.
+ *
+ * @param string $string the input string which may contain tabs
+ * @param int $tabSize one tab = how many spaces, a negative does nothing
+ * @param bool $onlyLeadingTabs only expand leading tabs
+ *
+ * @return string the string with the tabs converted to spaces
+ */
+ protected function expandTabs(string $string, int $tabSize = 4, bool $onlyLeadingTabs = false): string
+ {
+ if ($tabSize < 0) {
+ return $string;
+ }
+
+ if ($onlyLeadingTabs) {
+ return \preg_replace_callback(
+ "/^[ \t]{1,}/mS", // tabs and spaces may be mixed
+ function (array $matches) use ($tabSize): string {
+ return \str_replace("\t", \str_repeat(' ', $tabSize), $matches[0]);
+ },
+ $string
+ );
+ }
+
+ return \str_replace("\t", \str_repeat(' ', $tabSize), $string);
+ }
+
+ /**
+ * Make a string containing HTML safe for output on a page.
+ *
+ * @param string $string the string
+ *
+ * @return string the string with the HTML characters replaced by entities
+ */
+ protected function htmlSafe(string $string): string
+ {
+ return \htmlspecialchars($string, \ENT_NOQUOTES, 'UTF-8');
+ }
+
+ /**
+ * Replace a string containing spaces with a HTML representation having "&nbsp;".
+ *
+ * @param string $string the string of spaces
+ *
+ * @return string the HTML representation of the string
+ */
+ protected function htmlFixSpaces(string $string): string
+ {
+ return \preg_replace_callback(
+ '/ {2,}/S', // only fix for more than 1 space
+ function (array $matches): string {
+ $count = \strlen($matches[0]);
+
+ return \str_repeat(' &nbsp;', $count >> 1) . ($count & 1 ? ' ' : '');
+ },
+ $string
+ );
+ }
+
+ /**
+ * Make sure the "changes" array uses int "tag".
+ *
+ * Internally, we would like always int form for better performance.
+ *
+ * @param array[][] $changes the changes
+ */
+ protected function ensureChangesUseIntTag(array &$changes): void
+ {
+ // check if the tag is already int type
+ if (\is_int($changes[0][0]['tag'] ?? null)) {
+ return;
+ }
+
+ foreach ($changes as &$hunks) {
+ foreach ($hunks as &$block) {
+ $block['tag'] = SequenceMatcher::opStrToInt($block['tag']);
+ }
+ }
+ }
+
+ /**
+ * Clean up empty HTML closures in the given string.
+ *
+ * @param string $string the string
+ */
+ protected function cleanUpDummyHtmlClosures(string $string): string
+ {
+ return \str_replace(
+ [
+ RendererConstant::HTML_CLOSURES_DEL[0] . RendererConstant::HTML_CLOSURES_DEL[1],
+ RendererConstant::HTML_CLOSURES_INS[0] . RendererConstant::HTML_CLOSURES_INS[1],
+ ],
+ '',
+ $string
+ );
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/Combined.php b/vendor/jfcherng/php-diff/src/Renderer/Html/Combined.php
new file mode 100644
index 0000000..4baab68
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/Combined.php
@@ -0,0 +1,505 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+use Jfcherng\Diff\Factory\LineRendererFactory;
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Diff\SequenceMatcher;
+use Jfcherng\Diff\Utility\ReverseIterator;
+use Jfcherng\Utility\MbString;
+
+/**
+ * Combined HTML diff generator.
+ *
+ * Note that this renderer always has no line number.
+ */
+final class Combined extends AbstractHtml
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Combined',
+ 'type' => 'Html',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public const AUTO_FORMAT_CHANGES = false;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function redererChanges(array $changes): string
+ {
+ if (empty($changes)) {
+ return $this->getResultForIdenticals();
+ }
+
+ $wrapperClasses = \array_merge(
+ $this->options['wrapperClasses'],
+ ['diff', 'diff-html', 'diff-combined']
+ );
+
+ return
+ '<table class="' . \implode(' ', $wrapperClasses) . '">' .
+ $this->renderTableHeader() .
+ $this->renderTableHunks($changes) .
+ '</table>';
+ }
+
+ /**
+ * Renderer the table header.
+ */
+ protected function renderTableHeader(): string
+ {
+ if (!$this->options['showHeader']) {
+ return '';
+ }
+
+ return
+ '<thead>' .
+ '<tr>' .
+ '<th>' . $this->_('differences') . '</th>' .
+ '</tr>' .
+ '</thead>';
+ }
+
+ /**
+ * Renderer the table separate block.
+ */
+ protected function renderTableSeparateBlock(): string
+ {
+ return
+ '<tbody class="skipped">' .
+ '<tr>' .
+ '<td></td>' .
+ '</tr>' .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer table hunks.
+ *
+ * @param array[][] $hunks each hunk has many blocks
+ */
+ protected function renderTableHunks(array $hunks): string
+ {
+ $ret = '';
+
+ foreach ($hunks as $i => $hunk) {
+ if ($i > 0 && $this->options['separateBlock']) {
+ $ret .= $this->renderTableSeparateBlock();
+ }
+
+ foreach ($hunk as $block) {
+ $ret .= $this->renderTableBlock($block);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlock(array $block): string
+ {
+ static $callbacks = [
+ SequenceMatcher::OP_EQ => 'renderTableBlockEqual',
+ SequenceMatcher::OP_INS => 'renderTableBlockInsert',
+ SequenceMatcher::OP_DEL => 'renderTableBlockDelete',
+ SequenceMatcher::OP_REP => 'renderTableBlockReplace',
+ ];
+
+ return
+ '<tbody class="change change-' . self::TAG_CLASS_MAP[$block['tag']] . '">' .
+ $this->{$callbacks[$block['tag']]}($block) .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer the table block: equal.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockEqual(array $block): string
+ {
+ $block['new']['lines'] = $this->customFormatLines(
+ $block['new']['lines'],
+ SequenceMatcher::OP_EQ
+ );
+
+ $ret = '';
+
+ // note that although we are in a OP_EQ situation,
+ // the old and the new may not be exactly the same
+ // because of ignoreCase, ignoreWhitespace, etc
+ foreach ($block['new']['lines'] as $newLine) {
+ // we could only pick either the old or the new to show
+ // here we pick the new one to let the user know what it is now
+ $ret .= $this->renderTableRow('new', SequenceMatcher::OP_EQ, $newLine);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: insert.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockInsert(array $block): string
+ {
+ $block['new']['lines'] = $this->customFormatLines(
+ $block['new']['lines'],
+ SequenceMatcher::OP_INS
+ );
+
+ $ret = '';
+
+ foreach ($block['new']['lines'] as $newLine) {
+ $ret .= $this->renderTableRow('new', SequenceMatcher::OP_INS, $newLine);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: delete.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockDelete(array $block): string
+ {
+ $block['old']['lines'] = $this->customFormatLines(
+ $block['old']['lines'],
+ SequenceMatcher::OP_DEL
+ );
+
+ $ret = '';
+
+ foreach ($block['old']['lines'] as $oldLine) {
+ $ret .= $this->renderTableRow('old', SequenceMatcher::OP_DEL, $oldLine);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: replace.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockReplace(array $block): string
+ {
+ if ($this->options['detailLevel'] === 'none') {
+ return
+ $this->renderTableBlockDelete($block) .
+ $this->renderTableBlockInsert($block);
+ }
+
+ $ret = '';
+
+ $oldLines = $block['old']['lines'];
+ $newLines = $block['new']['lines'];
+
+ $oldLinesCount = \count($oldLines);
+ $newLinesCount = \count($newLines);
+
+ // if the line counts changes, we treat the old and the new as
+ // "a line with \n in it" and then do one-line-to-one-line diff
+ if ($oldLinesCount !== $newLinesCount) {
+ [$oldLines, $newLines] = $this->markReplaceBlockDiff($oldLines, $newLines);
+ $oldLinesCount = $newLinesCount = 1;
+ }
+
+ $oldLines = $this->customFormatLines($oldLines, SequenceMatcher::OP_DEL);
+ $newLines = $this->customFormatLines($newLines, SequenceMatcher::OP_INS);
+
+ // now $oldLines must has the same line counts with $newlines
+ for ($no = 0; $no < $newLinesCount; ++$no) {
+ $mergedLine = $this->mergeReplaceLines($oldLines[$no], $newLines[$no]);
+
+ // not merge-able, we fall back to separated form
+ if (!isset($mergedLine)) {
+ $ret .=
+ $this->renderTableBlockDelete($block) .
+ $this->renderTableBlockInsert($block);
+
+ continue;
+ }
+
+ $ret .= $this->renderTableRow('rep', SequenceMatcher::OP_REP, $mergedLine);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer a content row of the output table.
+ *
+ * @param string $tdClass the <td> class
+ * @param int $op the operation
+ * @param string $line the line
+ */
+ protected function renderTableRow(string $tdClass, int $op, string $line): string
+ {
+ return
+ '<tr data-type="' . self::SYMBOL_MAP[$op] . '">' .
+ '<td class="' . $tdClass . '">' . $line . '</td>' .
+ '</tr>';
+ }
+
+ /**
+ * Merge two "replace"-type lines into a single line.
+ *
+ * The implementation concept is that if we remove all closure parts from
+ * the old and the new, the rest of them (cleaned line) should be the same.
+ * And then, we add back those removed closure parts in a correct order.
+ *
+ * @param string $oldLine the old line
+ * @param string $newLine the new line
+ *
+ * @return null|string string if merge-able, null otherwise
+ */
+ protected function mergeReplaceLines(string $oldLine, string $newLine): ?string
+ {
+ $delParts = $this->analyzeClosureParts(
+ $oldLine,
+ RendererConstant::HTML_CLOSURES_DEL,
+ SequenceMatcher::OP_DEL
+ );
+ $insParts = $this->analyzeClosureParts(
+ $newLine,
+ RendererConstant::HTML_CLOSURES_INS,
+ SequenceMatcher::OP_INS
+ );
+
+ // get the cleaned line by a non-regex way (should be faster)
+ // i.e., the new line with all "<ins>...</ins>" parts removed
+ $mergedLine = $newLine;
+ foreach (ReverseIterator::fromArray($insParts) as $part) {
+ $mergedLine = \substr_replace(
+ $mergedLine,
+ '', // deletion
+ $part['offset'],
+ \strlen($part['content'])
+ );
+ }
+
+ // note that $mergedLine is actually a clean line at this point
+ if (!$this->isLinesMergeable($oldLine, $newLine, $mergedLine)) {
+ return null;
+ }
+
+ // before building the $mergedParts, we do some adjustments
+ $this->revisePartsForBoundaryNewlines($delParts, RendererConstant::HTML_CLOSURES_DEL);
+ $this->revisePartsForBoundaryNewlines($insParts, RendererConstant::HTML_CLOSURES_INS);
+
+ // create a sorted merged parts array
+ $mergedParts = \array_merge($delParts, $insParts);
+ \usort($mergedParts, function (array $a, array $b): int {
+ // first sort by "offsetClean", "order" then by "type"
+ return $a['offsetClean'] <=> $b['offsetClean']
+ ?: $a['order'] <=> $b['order']
+ ?: ($a['type'] === SequenceMatcher::OP_DEL ? -1 : 1);
+ });
+
+ // insert merged parts into the cleaned line
+ foreach (ReverseIterator::fromArray($mergedParts) as $part) {
+ $mergedLine = \substr_replace(
+ $mergedLine,
+ $part['content'],
+ $part['offsetClean'],
+ 0 // insertion
+ );
+ }
+
+ return \str_replace("\n", '<br>', $mergedLine);
+ }
+
+ /**
+ * Analyze and get the closure parts information of the line.
+ *
+ * Such as
+ * extract informations for "<ins>part 1</ins>" and "<ins>part 2</ins>"
+ * from "Hello <ins>part 1</ins>SOME OTHER TEXT<ins>part 2</ins> World"
+ *
+ * @param string $line the line
+ * @param string[] $closures the closures
+ * @param int $type the type
+ *
+ * @return array[] the closure informations
+ */
+ protected function analyzeClosureParts(string $line, array $closures, int $type): array
+ {
+ [$ld, $rd] = $closures;
+
+ $ldLength = \strlen($ld);
+ $rdLength = \strlen($rd);
+
+ $parts = [];
+ $partStart = $partEnd = 0;
+ $partLengthSum = 0;
+
+ // find the next left delimiter
+ while (false !== ($partStart = \strpos($line, $ld, $partEnd))) {
+ // find the corresponding right delimiter
+ if (false === ($partEnd = \strpos($line, $rd, $partStart + $ldLength))) {
+ break;
+ }
+
+ $partEnd += $rdLength;
+ $partLength = $partEnd - $partStart;
+
+ $parts[] = [
+ 'type' => $type,
+ // the sorting order used when both "offsetClean" are the same
+ 'order' => 0,
+ // the offset in the line
+ 'offset' => $partStart,
+ // the offset in the cleaned line (i.e., the line with closure parts removed)
+ 'offsetClean' => $partStart - $partLengthSum,
+ // the content of the part
+ 'content' => \substr($line, $partStart, $partLength),
+ ];
+
+ $partLengthSum += $partLength;
+ }
+
+ return $parts;
+ }
+
+ /**
+ * Mark differences between two "replace" blocks.
+ *
+ * Each of the returned block (lines) is always only one line.
+ *
+ * @param string[] $oldBlock The old block
+ * @param string[] $newBlock The new block
+ *
+ * @return string[][] the value of [[$oldLine], [$newLine]]
+ */
+ protected function markReplaceBlockDiff(array $oldBlock, array $newBlock): array
+ {
+ static $mbOld, $mbNew, $lineRenderer;
+
+ $mbOld = $mbOld ?? new MbString();
+ $mbNew = $mbNew ?? new MbString();
+ $lineRenderer = $lineRenderer ?? LineRendererFactory::make(
+ $this->options['detailLevel'],
+ [], /** @todo is it possible to get the differOptions here? */
+ $this->options
+ );
+
+ $mbOld->set(\implode("\n", $oldBlock));
+ $mbNew->set(\implode("\n", $newBlock));
+
+ $lineRenderer->render($mbOld, $mbNew);
+
+ return [
+ [$mbOld->get()], // one-line block for the old
+ [$mbNew->get()], // one-line block for the new
+ ];
+ }
+
+ /**
+ * Determine whether the "replace"-type lines are merge-able or not.
+ *
+ * @param string $oldLine the old line
+ * @param string $newLine the new line
+ * @param string $cleanLine the clean line
+ */
+ protected function isLinesMergeable(string $oldLine, string $newLine, string $cleanLine): bool
+ {
+ $oldLine = \str_replace(RendererConstant::HTML_CLOSURES_DEL, '', $oldLine);
+ $newLine = \str_replace(RendererConstant::HTML_CLOSURES_INS, '', $newLine);
+
+ $sumLength = \strlen($oldLine) + \strlen($newLine);
+
+ /** @var float the changed ratio, 0 <= value < 1 */
+ $changedRatio = ($sumLength - (\strlen($cleanLine) << 1)) / ($sumLength + 1);
+
+ return $changedRatio <= $this->options['mergeThreshold'];
+ }
+
+ /**
+ * Extract boundary newlines from parts into new parts.
+ *
+ * @param array[] $parts the parts
+ * @param string[] $closures the closures
+ *
+ * @see https://git.io/JvVXH
+ */
+ protected function revisePartsForBoundaryNewlines(array &$parts, array $closures): void
+ {
+ [$ld, $rd] = $closures;
+
+ $ldRegex = \preg_quote($ld, '/');
+ $rdRegex = \preg_quote($rd, '/');
+
+ for ($i = \count($parts) - 1; $i >= 0; --$i) {
+ $part = &$parts[$i];
+
+ // deal with leading newlines
+ $part['content'] = \preg_replace_callback(
+ "/(?P<closure>{$ldRegex})(?P<nl>[\r\n]++)/u",
+ function (array $matches) use (&$parts, $part, $ld, $rd): string {
+ // add a new part for the extracted newlines
+ $part['order'] = -1;
+ $part['content'] = "{$ld}{$matches['nl']}{$rd}";
+ $parts[] = $part;
+
+ return $matches['closure'];
+ },
+ $part['content']
+ );
+
+ // deal with trailing newlines
+ $part['content'] = \preg_replace_callback(
+ "/(?P<nl>[\r\n]++)(?P<closure>{$rdRegex})/u",
+ function (array $matches) use (&$parts, $part, $ld, $rd): string {
+ // add a new part for the extracted newlines
+ $part['order'] = 1;
+ $part['content'] = "{$ld}{$matches['nl']}{$rd}";
+ $parts[] = $part;
+
+ return $matches['closure'];
+ },
+ $part['content']
+ );
+ }
+ }
+
+ /**
+ * Make lines suitable for HTML output.
+ *
+ * @param string[] $lines the lines
+ * @param int $op the operation
+ */
+ protected function customFormatLines(array $lines, int $op): array
+ {
+ static $closureMap = [
+ SequenceMatcher::OP_DEL => RendererConstant::HTML_CLOSURES_DEL,
+ SequenceMatcher::OP_INS => RendererConstant::HTML_CLOSURES_INS,
+ ];
+
+ $lines = $this->formatLines($lines);
+
+ $htmlClosures = $closureMap[$op] ?? null;
+
+ foreach ($lines as &$line) {
+ if ($htmlClosures) {
+ $line = \str_replace(RendererConstant::HTML_CLOSURES, $htmlClosures, $line);
+ }
+ }
+
+ return $lines;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/Inline.php b/vendor/jfcherng/php-diff/src/Renderer/Html/Inline.php
new file mode 100644
index 0000000..d518b15
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/Inline.php
@@ -0,0 +1,259 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Inline HTML diff generator.
+ */
+final class Inline extends AbstractHtml
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Inline',
+ 'type' => 'Html',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function redererChanges(array $changes): string
+ {
+ if (empty($changes)) {
+ return $this->getResultForIdenticals();
+ }
+
+ $wrapperClasses = \array_merge(
+ $this->options['wrapperClasses'],
+ ['diff', 'diff-html', 'diff-inline']
+ );
+
+ return
+ '<table class="' . \implode(' ', $wrapperClasses) . '">' .
+ $this->renderTableHeader() .
+ $this->renderTableHunks($changes) .
+ '</table>';
+ }
+
+ /**
+ * Renderer the table header.
+ */
+ protected function renderTableHeader(): string
+ {
+ if (!$this->options['showHeader']) {
+ return '';
+ }
+
+ $colspan = $this->options['lineNumbers'] ? '' : ' colspan="2"';
+
+ return
+ '<thead>' .
+ '<tr>' .
+ (
+ $this->options['lineNumbers']
+ ?
+ '<th>' . $this->_('old_version') . '</th>' .
+ '<th>' . $this->_('new_version') . '</th>' .
+ '<th></th>' // diff symbol column
+ :
+ ''
+ ) .
+ '<th' . $colspan . '>' . $this->_('differences') . '</th>' .
+ '</tr>' .
+ '</thead>';
+ }
+
+ /**
+ * Renderer the table separate block.
+ */
+ protected function renderTableSeparateBlock(): string
+ {
+ $colspan = $this->options['lineNumbers'] ? '4' : '2';
+
+ return
+ '<tbody class="skipped">' .
+ '<tr>' .
+ '<td colspan="' . $colspan . '"></td>' .
+ '</tr>' .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer table hunks.
+ *
+ * @param array[][] $hunks each hunk has many blocks
+ */
+ protected function renderTableHunks(array $hunks): string
+ {
+ $ret = '';
+
+ foreach ($hunks as $i => $hunk) {
+ if ($i > 0 && $this->options['separateBlock']) {
+ $ret .= $this->renderTableSeparateBlock();
+ }
+
+ foreach ($hunk as $block) {
+ $ret .= $this->renderTableBlock($block);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlock(array $block): string
+ {
+ static $callbacks = [
+ SequenceMatcher::OP_EQ => 'renderTableBlockEqual',
+ SequenceMatcher::OP_INS => 'renderTableBlockInsert',
+ SequenceMatcher::OP_DEL => 'renderTableBlockDelete',
+ SequenceMatcher::OP_REP => 'renderTableBlockReplace',
+ ];
+
+ return
+ '<tbody class="change change-' . self::TAG_CLASS_MAP[$block['tag']] . '">' .
+ $this->{$callbacks[$block['tag']]}($block) .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer the table block: equal.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockEqual(array $block): string
+ {
+ $ret = '';
+
+ // note that although we are in a OP_EQ situation,
+ // the old and the new may not be exactly the same
+ // because of ignoreCase, ignoreWhitespace, etc
+ foreach ($block['new']['lines'] as $no => $newLine) {
+ // we could only pick either the old or the new to show
+ // here we pick the new one to let the user know what it is now
+ $ret .= $this->renderTableRow(
+ 'new',
+ SequenceMatcher::OP_EQ,
+ $newLine,
+ $block['old']['offset'] + $no + 1,
+ $block['new']['offset'] + $no + 1
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: insert.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockInsert(array $block): string
+ {
+ $ret = '';
+
+ foreach ($block['new']['lines'] as $no => $newLine) {
+ $ret .= $this->renderTableRow(
+ 'new',
+ SequenceMatcher::OP_INS,
+ $newLine,
+ null,
+ $block['new']['offset'] + $no + 1
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: delete.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockDelete(array $block): string
+ {
+ $ret = '';
+
+ foreach ($block['old']['lines'] as $no => $oldLine) {
+ $ret .= $this->renderTableRow(
+ 'old',
+ SequenceMatcher::OP_DEL,
+ $oldLine,
+ $block['old']['offset'] + $no + 1,
+ null
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: replace.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockReplace(array $block): string
+ {
+ return
+ $this->renderTableBlockDelete($block) .
+ $this->renderTableBlockInsert($block);
+ }
+
+ /**
+ * Renderer a content row of the output table.
+ *
+ * @param string $tdClass the <td> class
+ * @param int $op the operation
+ * @param string $line the line
+ * @param null|int $oldLineNum the old line number
+ * @param null|int $newLineNum the new line number
+ */
+ protected function renderTableRow(
+ string $tdClass,
+ int $op,
+ string $line,
+ ?int $oldLineNum,
+ ?int $newLineNum
+ ): string {
+ return
+ '<tr data-type="' . self::SYMBOL_MAP[$op] . '">' .
+ (
+ $this->options['lineNumbers']
+ ? $this->renderLineNumberColumns($oldLineNum, $newLineNum)
+ : ''
+ ) .
+ '<th class="sign ' . self::TAG_CLASS_MAP[$op] . '">' . self::SYMBOL_MAP[$op] . '</th>' .
+ '<td class="' . $tdClass . '">' . $line . '</td>' .
+ '</tr>';
+ }
+
+ /**
+ * Renderer the line number columns.
+ *
+ * @param null|int $oldLineNum The old line number
+ * @param null|int $newLineNum The new line number
+ */
+ protected function renderLineNumberColumns(?int $oldLineNum, ?int $newLineNum): string
+ {
+ return
+ (
+ isset($oldLineNum)
+ ? '<th class="n-old">' . $oldLineNum . '</th>'
+ : '<th></th>'
+ ) .
+ (
+ isset($newLineNum)
+ ? '<th class="n-new">' . $newLineNum . '</th>'
+ : '<th></th>'
+ );
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/Json.php b/vendor/jfcherng/php-diff/src/Renderer/Html/Json.php
new file mode 100644
index 0000000..27f8f36
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/Json.php
@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+/**
+ * HTML Json diff generator.
+ *
+ * @deprecated 6.8.0 Use the "JsonHtml" renderer instead.
+ */
+final class Json extends JsonHtml
+{
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/JsonHtml.php b/vendor/jfcherng/php-diff/src/Renderer/Html/JsonHtml.php
new file mode 100644
index 0000000..a7981a1
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/JsonHtml.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * HTML Json diff generator.
+ */
+class JsonHtml extends AbstractHtml
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'HTML Json',
+ 'type' => 'Html',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public const IS_TEXT_RENDERER = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResultForIdenticalsDefault(): string
+ {
+ return '[]';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function redererChanges(array $changes): string
+ {
+ if ($this->options['outputTagAsString']) {
+ $this->convertTagToString($changes);
+ }
+
+ return \json_encode($changes, $this->options['jsonEncodeFlags']);
+ }
+
+ /**
+ * Convert tags of changes to their string form for better readability.
+ *
+ * @param array[][] $changes the changes
+ */
+ protected function convertTagToString(array &$changes): void
+ {
+ foreach ($changes as &$hunks) {
+ foreach ($hunks as &$block) {
+ $block['tag'] = SequenceMatcher::opIntToStr($block['tag']);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function formatStringFromLines(string $string): string
+ {
+ return $this->htmlSafe($string);
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/AbstractLineRenderer.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/AbstractLineRenderer.php
new file mode 100644
index 0000000..5320994
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/AbstractLineRenderer.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Base renderer for rendering HTML-based line diffs.
+ */
+abstract class AbstractLineRenderer implements LineRendererInterface
+{
+ /**
+ * @var SequenceMatcher the sequence matcher
+ */
+ protected $sequenceMatcher;
+
+ /**
+ * @var array the differ options
+ */
+ protected $differOptions = [];
+
+ /**
+ * @var array the renderer options
+ */
+ protected $rendererOptions = [];
+
+ /**
+ * The constructor.
+ *
+ * @param array $differOptions the differ options
+ * @param array $rendererOptions the renderer options
+ */
+ public function __construct(array $differOptions, array $rendererOptions)
+ {
+ $this->sequenceMatcher = new SequenceMatcher([], []);
+
+ $this
+ ->setDifferOptions($differOptions)
+ ->setRendererOptions($rendererOptions);
+ }
+
+ /**
+ * Set the differ options.
+ *
+ * @param array $differOptions the differ options
+ *
+ * @return static
+ */
+ public function setDifferOptions(array $differOptions): self
+ {
+ $this->differOptions = $differOptions;
+ $this->sequenceMatcher->setOptions($differOptions);
+
+ return $this;
+ }
+
+ /**
+ * Set the renderer options.
+ *
+ * @param array $rendererOptions the renderer options
+ *
+ * @return static
+ */
+ public function setRendererOptions(array $rendererOptions): self
+ {
+ $this->rendererOptions = $rendererOptions;
+
+ return $this;
+ }
+
+ /**
+ * Gets the differ options.
+ *
+ * @return array the differ options
+ */
+ public function getDifferOptions(): array
+ {
+ return $this->differOptions;
+ }
+
+ /**
+ * Gets the renderer options.
+ *
+ * @return array the renderer options
+ */
+ public function getRendererOptions(): array
+ {
+ return $this->rendererOptions;
+ }
+
+ /**
+ * Get the changed extent segments.
+ *
+ * @param string[] $old the old array
+ * @param string[] $new the new array
+ *
+ * @return int[][] the changed extent segments
+ */
+ protected function getChangedExtentSegments(array $old, array $new): array
+ {
+ return $this->sequenceMatcher->setSequences($old, $new)->getOpcodes();
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Char.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Char.php
new file mode 100644
index 0000000..f66daba
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Char.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Diff\SequenceMatcher;
+use Jfcherng\Diff\Utility\ReverseIterator;
+use Jfcherng\Utility\MbString;
+
+final class Char extends AbstractLineRenderer
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @return static
+ */
+ public function render(MbString $mbOld, MbString $mbNew): LineRendererInterface
+ {
+ $hunk = $this->getChangedExtentSegments($mbOld->toArray(), $mbNew->toArray());
+
+ // reversely iterate hunk
+ foreach (ReverseIterator::fromArray($hunk) as [$op, $i1, $i2, $j1, $j2]) {
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_DEL)) {
+ $mbOld->str_enclose_i(RendererConstant::HTML_CLOSURES, $i1, $i2 - $i1);
+ }
+
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_INS)) {
+ $mbNew->str_enclose_i(RendererConstant::HTML_CLOSURES, $j1, $j2 - $j1);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Line.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Line.php
new file mode 100644
index 0000000..8e76c24
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Line.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Utility\MbString;
+
+final class Line extends AbstractLineRenderer
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @return static
+ */
+ public function render(MbString $mbOld, MbString $mbNew): LineRendererInterface
+ {
+ [$start, $end] = $this->getChangedExtentRegion($mbOld, $mbNew);
+
+ // two strings are the same
+ if ($end === 0) {
+ return $this;
+ }
+
+ // two strings are different, we do rendering
+ $mbOld->str_enclose_i(
+ RendererConstant::HTML_CLOSURES,
+ $start,
+ $end + $mbOld->strlen() - $start + 1
+ );
+ $mbNew->str_enclose_i(
+ RendererConstant::HTML_CLOSURES,
+ $start,
+ $end + $mbNew->strlen() - $start + 1
+ );
+
+ return $this;
+ }
+
+ /**
+ * Given two strings, determine where the changes in the two strings begin,
+ * and where the changes in the two strings end.
+ *
+ * @param MbString $mbOld the old megabytes line
+ * @param MbString $mbNew the new megabytes line
+ *
+ * @return int[] Array containing the starting position (non-negative) and the ending position (negative)
+ * [0, 0] if two strings are the same
+ */
+ protected function getChangedExtentRegion(MbString $mbOld, MbString $mbNew): array
+ {
+ // two strings are the same
+ // most lines should be this cases, an early return could save many function calls
+ if ($mbOld->getRaw() === $mbNew->getRaw()) {
+ return [0, 0];
+ }
+
+ // calculate $start
+ $start = 0;
+ $startMax = \min($mbOld->strlen(), $mbNew->strlen());
+ while (
+ $start < $startMax // index out of range
+ && $mbOld->getAtRaw($start) === $mbNew->getAtRaw($start)
+ ) {
+ ++$start;
+ }
+
+ // calculate $end
+ $end = -1; // trick
+ $endMin = $startMax - $start;
+ while (
+ -$end <= $endMin // index out of range
+ && $mbOld->getAtRaw($end) === $mbNew->getAtRaw($end)
+ ) {
+ --$end;
+ }
+
+ return [$start, $end];
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/LineRendererInterface.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/LineRendererInterface.php
new file mode 100644
index 0000000..4437fcb
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/LineRendererInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Utility\MbString;
+
+interface LineRendererInterface
+{
+ /**
+ * Renderer the in-line changed extent.
+ *
+ * @param MbString $mbOld the old megabytes line
+ * @param MbString $mbNew the new megabytes line
+ *
+ * @return static
+ */
+ public function render(MbString $mbOld, MbString $mbNew): self;
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/None.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/None.php
new file mode 100644
index 0000000..b8abaa5
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/None.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Utility\MbString;
+
+final class None extends AbstractLineRenderer
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @return static
+ */
+ public function render(MbString $mbOld, MbString $mbNew): LineRendererInterface
+ {
+ return $this;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Word.php b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Word.php
new file mode 100644
index 0000000..b9e83f8
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/LineRenderer/Word.php
@@ -0,0 +1,110 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html\LineRenderer;
+
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Diff\SequenceMatcher;
+use Jfcherng\Diff\Utility\ReverseIterator;
+use Jfcherng\Diff\Utility\Str;
+use Jfcherng\Utility\MbString;
+
+final class Word extends AbstractLineRenderer
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @return static
+ */
+ public function render(MbString $mbOld, MbString $mbNew): LineRendererInterface
+ {
+ static $splitRegex = '/([' . RendererConstant::PUNCTUATIONS_RANGE . '])/uS';
+ static $dummyHtmlClosure = RendererConstant::HTML_CLOSURES[0] . RendererConstant::HTML_CLOSURES[1];
+
+ $pregFlag = \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY;
+ $oldWords = $mbOld->toArraySplit($splitRegex, -1, $pregFlag);
+ $newWords = $mbNew->toArraySplit($splitRegex, -1, $pregFlag);
+
+ $hunk = $this->getChangedExtentSegments($oldWords, $newWords);
+
+ // reversely iterate hunk
+ foreach (ReverseIterator::fromArray($hunk) as [$op, $i1, $i2, $j1, $j2]) {
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_DEL)) {
+ $oldWords[$i1] = RendererConstant::HTML_CLOSURES[0] . $oldWords[$i1];
+ $oldWords[$i2 - 1] .= RendererConstant::HTML_CLOSURES[1];
+
+ // insert dummy HTML closure to ensure there are always
+ // the same amounts of HTML closures in $oldWords and $newWords
+ // thus, this should make that "wordGlues" work correctly
+ // @see https://github.com/jfcherng/php-diff/pull/25
+ if ($op === SequenceMatcher::OP_DEL) {
+ \array_splice($newWords, $j1, 0, [$dummyHtmlClosure]);
+ }
+ }
+
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_INS)) {
+ $newWords[$j1] = RendererConstant::HTML_CLOSURES[0] . $newWords[$j1];
+ $newWords[$j2 - 1] .= RendererConstant::HTML_CLOSURES[1];
+
+ if ($op === SequenceMatcher::OP_INS) {
+ \array_splice($oldWords, $i1, 0, [$dummyHtmlClosure]);
+ }
+ }
+ }
+
+ if (!empty($hunk) && !empty($this->rendererOptions['wordGlues'])) {
+ $regexGlues = \array_map(
+ function (string $glue): string {
+ return \preg_quote($glue, '/');
+ },
+ $this->rendererOptions['wordGlues']
+ );
+
+ $gluePattern = '/^(?:' . \implode('|', $regexGlues) . ')+$/uS';
+
+ $this->glueWordsResult($oldWords, $gluePattern);
+ $this->glueWordsResult($newWords, $gluePattern);
+ }
+
+ $mbOld->set(\implode('', $oldWords));
+ $mbNew->set(\implode('', $newWords));
+
+ return $this;
+ }
+
+ /**
+ * Beautify diff result by glueing words.
+ *
+ * What this function does is basically making
+ * ["<diff_begin>good<diff_end>", "-", "<diff_begin>looking<diff_end>"]
+ * into
+ * ["<diff_begin>good", "-", "looking<diff_end>"].
+ *
+ * @param array $words the words
+ * @param string $gluePattern the regex to determine a string is purely glue or not
+ */
+ protected function glueWordsResult(array &$words, string $gluePattern): void
+ {
+ /** @var int index of the word which has the trailing closure */
+ $endClosureIdx = -1;
+
+ foreach ($words as $idx => &$word) {
+ if ($word === '') {
+ continue;
+ }
+
+ if ($endClosureIdx < 0) {
+ if (Str::endsWith($word, RendererConstant::HTML_CLOSURES[1])) {
+ $endClosureIdx = $idx;
+ }
+ } elseif (Str::startsWith($word, RendererConstant::HTML_CLOSURES[0])) {
+ $words[$endClosureIdx] = \substr($words[$endClosureIdx], 0, -\strlen(RendererConstant::HTML_CLOSURES[1]));
+ $word = \substr($word, \strlen(RendererConstant::HTML_CLOSURES[0]));
+ $endClosureIdx = $idx;
+ } elseif (!\preg_match($gluePattern, $word)) {
+ $endClosureIdx = -1;
+ }
+ }
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Html/SideBySide.php b/vendor/jfcherng/php-diff/src/Renderer/Html/SideBySide.php
new file mode 100644
index 0000000..b5371a3
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Html/SideBySide.php
@@ -0,0 +1,274 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Html;
+
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Side by Side HTML diff generator.
+ */
+final class SideBySide extends AbstractHtml
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Side by side',
+ 'type' => 'Html',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function redererChanges(array $changes): string
+ {
+ if (empty($changes)) {
+ return $this->getResultForIdenticals();
+ }
+
+ $wrapperClasses = \array_merge(
+ $this->options['wrapperClasses'],
+ ['diff', 'diff-html', 'diff-side-by-side']
+ );
+
+ return
+ '<table class="' . \implode(' ', $wrapperClasses) . '">' .
+ $this->renderTableHeader() .
+ $this->renderTableHunks($changes) .
+ '</table>';
+ }
+
+ /**
+ * Renderer the table header.
+ */
+ protected function renderTableHeader(): string
+ {
+ if (!$this->options['showHeader']) {
+ return '';
+ }
+
+ $colspan = $this->options['lineNumbers'] ? ' colspan="2"' : '';
+
+ return
+ '<thead>' .
+ '<tr>' .
+ '<th' . $colspan . '>' . $this->_('old_version') . '</th>' .
+ '<th' . $colspan . '>' . $this->_('new_version') . '</th>' .
+ '</tr>' .
+ '</thead>';
+ }
+
+ /**
+ * Renderer the table separate block.
+ */
+ protected function renderTableSeparateBlock(): string
+ {
+ $colspan = $this->options['lineNumbers'] ? '4' : '2';
+
+ return
+ '<tbody class="skipped">' .
+ '<tr>' .
+ '<td colspan="' . $colspan . '"></td>' .
+ '</tr>' .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer table hunks.
+ *
+ * @param array[][] $hunks each hunk has many blocks
+ */
+ protected function renderTableHunks(array $hunks): string
+ {
+ $ret = '';
+
+ foreach ($hunks as $i => $hunk) {
+ if ($i > 0 && $this->options['separateBlock']) {
+ $ret .= $this->renderTableSeparateBlock();
+ }
+
+ foreach ($hunk as $block) {
+ $ret .= $this->renderTableBlock($block);
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlock(array $block): string
+ {
+ static $callbacks = [
+ SequenceMatcher::OP_EQ => 'renderTableBlockEqual',
+ SequenceMatcher::OP_INS => 'renderTableBlockInsert',
+ SequenceMatcher::OP_DEL => 'renderTableBlockDelete',
+ SequenceMatcher::OP_REP => 'renderTableBlockReplace',
+ ];
+
+ return
+ '<tbody class="change change-' . self::TAG_CLASS_MAP[$block['tag']] . '">' .
+ $this->{$callbacks[$block['tag']]}($block) .
+ '</tbody>';
+ }
+
+ /**
+ * Renderer the table block: equal.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockEqual(array $block): string
+ {
+ $ret = '';
+
+ $rowCount = \count($block['new']['lines']);
+
+ for ($no = 0; $no < $rowCount; ++$no) {
+ $ret .= $this->renderTableRow(
+ $block['old']['lines'][$no],
+ $block['new']['lines'][$no],
+ $block['old']['offset'] + $no + 1,
+ $block['new']['offset'] + $no + 1
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: insert.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockInsert(array $block): string
+ {
+ $ret = '';
+
+ foreach ($block['new']['lines'] as $no => $newLine) {
+ $ret .= $this->renderTableRow(
+ null,
+ $newLine,
+ null,
+ $block['new']['offset'] + $no + 1
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: delete.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockDelete(array $block): string
+ {
+ $ret = '';
+
+ foreach ($block['old']['lines'] as $no => $oldLine) {
+ $ret .= $this->renderTableRow(
+ $oldLine,
+ null,
+ $block['old']['offset'] + $no + 1,
+ null
+ );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer the table block: replace.
+ *
+ * @param array $block the block
+ */
+ protected function renderTableBlockReplace(array $block): string
+ {
+ $ret = '';
+
+ $lineCountMax = \max(\count($block['old']['lines']), \count($block['new']['lines']));
+
+ for ($no = 0; $no < $lineCountMax; ++$no) {
+ if (isset($block['old']['lines'][$no])) {
+ $oldLineNum = $block['old']['offset'] + $no + 1;
+ $oldLine = $block['old']['lines'][$no];
+ } else {
+ $oldLineNum = $oldLine = null;
+ }
+
+ if (isset($block['new']['lines'][$no])) {
+ $newLineNum = $block['new']['offset'] + $no + 1;
+ $newLine = $block['new']['lines'][$no];
+ } else {
+ $newLineNum = $newLine = null;
+ }
+
+ $ret .= $this->renderTableRow($oldLine, $newLine, $oldLineNum, $newLineNum);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Renderer a content row of the output table.
+ *
+ * @param null|string $oldLine the old line
+ * @param null|string $newLine the new line
+ * @param null|int $oldLineNum the old line number
+ * @param null|int $newLineNum the new line number
+ */
+ protected function renderTableRow(
+ ?string $oldLine,
+ ?string $newLine,
+ ?int $oldLineNum,
+ ?int $newLineNum
+ ): string {
+ return
+ '<tr>' .
+ (
+ $this->options['lineNumbers']
+ ? $this->renderLineNumberColumn('old', $oldLineNum)
+ : ''
+ ) .
+ $this->renderLineContentColumn('old', $oldLine) .
+ (
+ $this->options['lineNumbers']
+ ? $this->renderLineNumberColumn('new', $newLineNum)
+ : ''
+ ) .
+ $this->renderLineContentColumn('new', $newLine) .
+ '</tr>';
+ }
+
+ /**
+ * Renderer the line number column.
+ *
+ * @param string $type the diff type
+ * @param null|int $lineNum the line number
+ */
+ protected function renderLineNumberColumn(string $type, ?int $lineNum): string
+ {
+ return isset($lineNum)
+ ? '<th class="n-' . $type . '">' . $lineNum . '</th>'
+ : '<th></th>';
+ }
+
+ /**
+ * Renderer the line content column.
+ *
+ * @param string $type the diff type
+ * @param null|string $content the line content
+ */
+ protected function renderLineContentColumn(string $type, ?string $content): string
+ {
+ return
+ '<td class="' . $type . (isset($content) ? '' : ' none') . '">' .
+ $content .
+ '</td>';
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/RendererConstant.php b/vendor/jfcherng/php-diff/src/Renderer/RendererConstant.php
new file mode 100644
index 0000000..a6d2481
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/RendererConstant.php
@@ -0,0 +1,116 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer;
+
+final class RendererConstant
+{
+ /**
+ * The base namespace of renderers.
+ *
+ * @var string
+ */
+ public const RENDERER_NAMESPACE = __NAMESPACE__;
+
+ /**
+ * Available renderer types.
+ *
+ * @var string[]
+ */
+ public const RENDERER_TYPES = ['Html', 'Text'];
+
+ /**
+ * Closures that are used to enclose different parts in string.
+ *
+ * Arbitrary chars from the 15-16th Unicode reserved areas
+ * and hopefully, they won't appear in source texts.
+ *
+ * @var string[]
+ */
+ public const HTML_CLOSURES = ["\u{fcffc}\u{ff2fb}", "\u{fff41}\u{fcffc}"];
+
+ /**
+ * Closures that are used to enclose deleted chars in output HTML.
+ *
+ * @var string[]
+ */
+ public const HTML_CLOSURES_DEL = ['<del>', '</del>'];
+
+ /**
+ * Closures that are used to enclose inserted chars in output HTML.
+ *
+ * @var string[]
+ */
+ public const HTML_CLOSURES_INS = ['<ins>', '</ins>'];
+
+ /**
+ * The delimiter to be used as the glue in string/array functions.
+ *
+ * Arbitrary chars from the 15-16th Unicode reserved areas
+ * and hopefully, it won't appear in source texts.
+ *
+ * @var string
+ */
+ public const IMPLODE_DELIMITER = "\u{ff2fa}\u{fcffc}\u{fff42}";
+
+ /**
+ * Regex range for punctuations.
+ *
+ * Presuming the regex delimiter is "/".
+ *
+ * @var string
+ */
+ public const PUNCTUATIONS_RANGE = (
+ // Latin-1 Supplement
+ // @see https://unicode-table.com/en/blocks/latin-1-supplement/
+ "\u{0080}-\u{00BB}" .
+ // Spacing Modifier Letters
+ // @see https://unicode-table.com/en/blocks/spacing-modifier-letters/
+ "\u{02B0}-\u{02FF}" .
+ // Combining Diacritical Marks
+ // @see https://unicode-table.com/en/blocks/combining-diacritical-marks/
+ "\u{0300}-\u{036F}" .
+ // Small Form Variants
+ // @see https://unicode-table.com/en/blocks/small-form-variants/
+ "\u{FE50}-\u{FE6F}" .
+ // General Punctuation
+ // @see https://unicode-table.com/en/blocks/general-punctuation/
+ "\u{2000}-\u{206F}" .
+ // Supplemental Punctuation
+ // @see https://unicode-table.com/en/blocks/supplemental-punctuation/
+ "\u{2E00}-\u{2E7F}" .
+ // CJK Symbols and Punctuation
+ // @see https://unicode-table.com/en/blocks/cjk-symbols-and-punctuation/
+ "\u{3000}-\u{303F}" .
+ // Ideographic Symbols and Punctuation
+ // @see https://unicode-table.com/en/blocks/ideographic-symbols-and-punctuation/
+ "\u{16FE0}-\u{16FFF}" .
+ // hmm... these seem to be no rule
+ " \t\r\n$,.:;!?'\"()\\[\\]{}%@<=>_+\\-*\\/~\\\\|" .
+ ' $,.:;!?’"()[]{}%@<=>_+-*/~\|' .
+ '「」『』〈〉《》【】()()‘’“”' .
+ '.‧・・•·¿'
+ );
+
+ /**
+ * Colorize the CLI output if possible.
+ *
+ * @var int
+ */
+ public const CLI_COLOR_AUTO = -1;
+
+ /**
+ * Force not to colorize the CLI output.
+ *
+ * @var int
+ */
+ public const CLI_COLOR_DISABLE = 0;
+
+ /**
+ * Force to colorize the CLI output if possible.
+ *
+ * @var int
+ */
+ public const CLI_COLOR_ENABLE = 1;
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/RendererInterface.php b/vendor/jfcherng/php-diff/src/Renderer/RendererInterface.php
new file mode 100644
index 0000000..97c109c
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/RendererInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\Exception\UnsupportedFunctionException;
+
+/**
+ * Renderer Interface.
+ */
+interface RendererInterface
+{
+ /**
+ * Get the renderer result when the old and the new are the same.
+ */
+ public function getResultForIdenticals(): string;
+
+ /**
+ * Render the differ and return the result.
+ *
+ * @param Differ $differ the Differ object to be rendered
+ */
+ public function render(Differ $differ): string;
+
+ /**
+ * Render the differ array and return the result.
+ *
+ * @param array[][] $differArray the Differ array to be rendered
+ *
+ * @throws UnsupportedFunctionException if the renderer does not support this method
+ */
+ public function renderArray(array $differArray): string;
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php b/vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php
new file mode 100644
index 0000000..b2f3f6c
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Text/AbstractText.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Text;
+
+use Jfcherng\Diff\Exception\UnsupportedFunctionException;
+use Jfcherng\Diff\Renderer\AbstractRenderer;
+use Jfcherng\Diff\Renderer\RendererConstant;
+use Jfcherng\Utility\CliColor;
+
+/**
+ * Base renderer for rendering text-based diffs.
+ */
+abstract class AbstractText extends AbstractRenderer
+{
+ /**
+ * @var bool is this renderer pure text?
+ */
+ public const IS_TEXT_RENDERER = true;
+
+ /**
+ * @var string the diff output representing there is no EOL at EOF in the GNU diff tool
+ */
+ public const GNU_OUTPUT_NO_EOL_AT_EOF = '\ No newline at end of file';
+
+ /**
+ * @var bool controls whether cliColoredString() is enabled or not
+ */
+ protected $isCliColorEnabled = false;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setOptions(array $options): AbstractRenderer
+ {
+ parent::setOptions($options);
+
+ // determine $this->isCliColorEnabled
+ if ($this->options['cliColorization'] === RendererConstant::CLI_COLOR_ENABLE) {
+ $this->isCliColorEnabled = true;
+ } elseif ($this->options['cliColorization'] === RendererConstant::CLI_COLOR_DISABLE) {
+ $this->isCliColorEnabled = false;
+ } else {
+ $this->isCliColorEnabled = \PHP_SAPI === 'cli' && $this->hasColorSupport(\STDOUT);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResultForIdenticalsDefault(): string
+ {
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderArrayWorker(array $differArray): string
+ {
+ throw new UnsupportedFunctionException(__METHOD__);
+
+ return ''; // make IDE not complain
+ }
+
+ /**
+ * Colorize the string for CLI output.
+ *
+ * @param string $str the string
+ * @param null|string $symbol the symbol
+ *
+ * @return string the (maybe) colorized string
+ */
+ protected function cliColoredString(string $str, ?string $symbol): string
+ {
+ static $symbolToStyles = [
+ '@' => ['f_purple', 'bold'], // header
+ '-' => ['f_red', 'bold'], // deleted
+ '+' => ['f_green', 'bold'], // inserted
+ '!' => ['f_yellow', 'bold'], // replaced
+ ];
+
+ $styles = $symbolToStyles[$symbol] ?? [];
+
+ if (!$this->isCliColorEnabled || empty($styles)) {
+ return $str;
+ }
+
+ return CliColor::color($str, $styles);
+ }
+
+ /**
+ * Returns true if the stream supports colorization.
+ *
+ * Colorization is disabled if not supported by the stream:
+ *
+ * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
+ * terminals via named pipes, so we can only check the environment.
+ *
+ * Reference: Composer\XdebugHandler\Process::supportsColor
+ * https://github.com/composer/xdebug-handler
+ *
+ * @see https://github.com/symfony/console/blob/647c51ff073300a432a4a504e29323cf0d5e0571/Output/StreamOutput.php#L81-L124
+ *
+ * @param resource $stream
+ *
+ * @return bool true if the stream supports colorization, false otherwise
+ *
+ * @suppress PhanUndeclaredFunction
+ */
+ protected function hasColorSupport($stream): bool
+ {
+ // Follow https://no-color.org/
+ if (isset($_SERVER['NO_COLOR']) || false !== \getenv('NO_COLOR')) {
+ return false;
+ }
+
+ if ('Hyper' === \getenv('TERM_PROGRAM')) {
+ return true;
+ }
+
+ if (\DIRECTORY_SEPARATOR === '\\') {
+ return (\function_exists('sapi_windows_vt100_support')
+ && @\sapi_windows_vt100_support($stream))
+ || false !== \getenv('ANSICON')
+ || 'ON' === \getenv('ConEmuANSI')
+ || 'xterm' === \getenv('TERM');
+ }
+
+ if (\function_exists('stream_isatty')) {
+ return @\stream_isatty($stream);
+ }
+
+ if (\function_exists('posix_isatty')) {
+ return @posix_isatty($stream);
+ }
+
+ $stat = @\fstat($stream);
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php b/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php
new file mode 100644
index 0000000..ddc9b2a
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Text/Context.php
@@ -0,0 +1,163 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Text;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Context diff generator.
+ *
+ * @see https://en.wikipedia.org/wiki/Diff#Context_format
+ */
+final class Context extends AbstractText
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Context',
+ 'type' => 'Text',
+ ];
+
+ /**
+ * @var int the union of OPs that indicate there is a change
+ */
+ public const OP_BLOCK_CHANGED =
+ SequenceMatcher::OP_DEL |
+ SequenceMatcher::OP_INS |
+ SequenceMatcher::OP_REP;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderWorker(Differ $differ): string
+ {
+ $ret = '';
+
+ foreach ($differ->getGroupedOpcodesGnu() as $hunk) {
+ $lastBlockIdx = \count($hunk) - 1;
+
+ // note that these line number variables are 0-based
+ $i1 = $hunk[0][1];
+ $i2 = $hunk[$lastBlockIdx][2];
+ $j1 = $hunk[0][3];
+ $j2 = $hunk[$lastBlockIdx][4];
+
+ $ret .=
+ $this->cliColoredString("***************\n", '@') .
+ $this->renderHunkHeader('*', $i1, $i2) .
+ $this->renderHunkOld($differ, $hunk) .
+ $this->renderHunkHeader('-', $j1, $j2) .
+ $this->renderHunkNew($differ, $hunk);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Render the hunk header.
+ *
+ * @param string $symbol the symbol
+ * @param int $a1 the begin index
+ * @param int $a2 the end index
+ */
+ protected function renderHunkHeader(string $symbol, int $a1, int $a2): string
+ {
+ $a1x = $a1 + 1; // 1-based begin line number
+
+ return $this->cliColoredString(
+ "{$symbol}{$symbol}{$symbol} " .
+ ($a1x < $a2 ? "{$a1x},{$a2}" : $a2) .
+ " {$symbol}{$symbol}{$symbol}{$symbol}\n",
+ '@' // symbol
+ );
+ }
+
+ /**
+ * Render the old hunk.
+ *
+ * @param Differ $differ the differ object
+ * @param int[][] $hunk the hunk
+ */
+ protected function renderHunkOld(Differ $differ, array $hunk): string
+ {
+ $ret = '';
+ $hunkOps = 0;
+ $noEolAtEofIdx = $differ->getOldNoEolAtEofIdx();
+
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ // OP_INS does not belongs to an old hunk
+ if ($op === SequenceMatcher::OP_INS) {
+ continue;
+ }
+
+ $hunkOps |= $op;
+
+ $ret .= $this->renderContext(
+ self::SYMBOL_MAP[$op],
+ $differ->getOld($i1, $i2),
+ $i2 === $noEolAtEofIdx
+ );
+ }
+
+ // if there is no content changed, the hunk context should be omitted
+ return $hunkOps & self::OP_BLOCK_CHANGED ? $ret : '';
+ }
+
+ /**
+ * Render the new hunk.
+ *
+ * @param Differ $differ the differ object
+ * @param int[][] $hunk the hunk
+ */
+ protected function renderHunkNew(Differ $differ, array $hunk): string
+ {
+ $ret = '';
+ $hunkOps = 0;
+ $noEolAtEofIdx = $differ->getNewNoEolAtEofIdx();
+
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ // OP_DEL does not belongs to a new hunk
+ if ($op === SequenceMatcher::OP_DEL) {
+ continue;
+ }
+
+ $hunkOps |= $op;
+
+ $ret .= $this->renderContext(
+ self::SYMBOL_MAP[$op],
+ $differ->getNew($j1, $j2),
+ $j2 === $noEolAtEofIdx
+ );
+ }
+
+ // if there is no content changed, the hunk context should be omitted
+ return $hunkOps & self::OP_BLOCK_CHANGED ? $ret : '';
+ }
+
+ /**
+ * Render the context array with the symbol.
+ *
+ * @param string $symbol the symbol
+ * @param string[] $context the context
+ * @param bool $noEolAtEof there is no EOL at EOF in this block
+ */
+ protected function renderContext(string $symbol, array $context, bool $noEolAtEof = false): string
+ {
+ if (empty($context)) {
+ return '';
+ }
+
+ $ret = "{$symbol} " . \implode("\n{$symbol} ", $context) . "\n";
+ $ret = $this->cliColoredString($ret, $symbol);
+
+ if ($noEolAtEof) {
+ $ret .= self::GNU_OUTPUT_NO_EOL_AT_EOF . "\n";
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php b/vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php
new file mode 100644
index 0000000..b99aa56
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Text/JsonText.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Text;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Plain text Json diff generator.
+ */
+final class JsonText extends AbstractText
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Text JSON',
+ 'type' => 'Text',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderWorker(Differ $differ): string
+ {
+ $ret = [];
+
+ foreach ($differ->getGroupedOpcodes() as $hunk) {
+ $ret[] = $this->renderHunk($differ, $hunk);
+ }
+
+ if ($this->options['outputTagAsString']) {
+ $this->convertTagToString($ret);
+ }
+
+ return \json_encode($ret, $this->options['jsonEncodeFlags']);
+ }
+
+ /**
+ * Render the hunk.
+ *
+ * @param Differ $differ the differ object
+ * @param int[][] $hunk the hunk
+ */
+ protected function renderHunk(Differ $differ, array $hunk): array
+ {
+ $ret = [];
+
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ $ret[] = [
+ 'tag' => $op,
+ 'old' => [
+ 'offset' => $i1,
+ 'lines' => $differ->getOld($i1, $i2),
+ ],
+ 'new' => [
+ 'offset' => $j1,
+ 'lines' => $differ->getNew($j1, $j2),
+ ],
+ ];
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Convert tags of changes to their string form for better readability.
+ *
+ * @param array[][] $changes the changes
+ */
+ protected function convertTagToString(array &$changes): void
+ {
+ foreach ($changes as &$hunks) {
+ foreach ($hunks as &$block) {
+ $block['tag'] = SequenceMatcher::opIntToStr($block['tag']);
+ }
+ }
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php b/vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php
new file mode 100644
index 0000000..e211715
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Renderer/Text/Unified.php
@@ -0,0 +1,147 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Renderer\Text;
+
+use Jfcherng\Diff\Differ;
+use Jfcherng\Diff\SequenceMatcher;
+
+/**
+ * Unified diff generator.
+ *
+ * @see https://en.wikipedia.org/wiki/Diff#Unified_format
+ */
+final class Unified extends AbstractText
+{
+ /**
+ * {@inheritdoc}
+ */
+ public const INFO = [
+ 'desc' => 'Unified',
+ 'type' => 'Text',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderWorker(Differ $differ): string
+ {
+ $ret = '';
+
+ foreach ($differ->getGroupedOpcodesGnu() as $hunk) {
+ $ret .= $this->renderHunkHeader($differ, $hunk);
+ $ret .= $this->renderHunkBlocks($differ, $hunk);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Render the hunk header.
+ *
+ * @param Differ $differ the differ
+ * @param int[][] $hunk the hunk
+ */
+ protected function renderHunkHeader(Differ $differ, array $hunk): string
+ {
+ $lastBlockIdx = \count($hunk) - 1;
+
+ // note that these line number variables are 0-based
+ $i1 = $hunk[0][1];
+ $i2 = $hunk[$lastBlockIdx][2];
+ $j1 = $hunk[0][3];
+ $j2 = $hunk[$lastBlockIdx][4];
+
+ $oldLinesCount = $i2 - $i1;
+ $newLinesCount = $j2 - $j1;
+
+ return $this->cliColoredString(
+ '@@' .
+ ' -' .
+ // the line number in GNU diff is 1-based, so we add 1
+ // a special case is when a hunk has only changed blocks,
+ // i.e., context is set to 0, we do not need the adding
+ ($i1 === $i2 ? $i1 : $i1 + 1) .
+ // if the line counts is 1, it can (and mostly) be omitted
+ ($oldLinesCount === 1 ? '' : ",{$oldLinesCount}") .
+ ' +' .
+ ($j1 === $j2 ? $j1 : $j1 + 1) .
+ ($newLinesCount === 1 ? '' : ",{$newLinesCount}") .
+ " @@\n",
+ '@' // symbol
+ );
+ }
+
+ /**
+ * Render the hunk content.
+ *
+ * @param Differ $differ the differ
+ * @param int[][] $hunk the hunk
+ */
+ protected function renderHunkBlocks(Differ $differ, array $hunk): string
+ {
+ $ret = '';
+
+ $oldNoEolAtEofIdx = $differ->getOldNoEolAtEofIdx();
+ $newNoEolAtEofIdx = $differ->getNewNoEolAtEofIdx();
+
+ foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
+ // note that although we are in a OP_EQ situation,
+ // the old and the new may not be exactly the same
+ // because of ignoreCase, ignoreWhitespace, etc
+ if ($op === SequenceMatcher::OP_EQ) {
+ // we could only pick either the old or the new to show
+ // note that the GNU diff will use the old one because it creates a patch
+ $ret .= $this->renderContext(
+ ' ',
+ $differ->getOld($i1, $i2),
+ $i2 === $oldNoEolAtEofIdx
+ );
+
+ continue;
+ }
+
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_DEL)) {
+ $ret .= $this->renderContext(
+ '-',
+ $differ->getOld($i1, $i2),
+ $i2 === $oldNoEolAtEofIdx
+ );
+ }
+
+ if ($op & (SequenceMatcher::OP_REP | SequenceMatcher::OP_INS)) {
+ $ret .= $this->renderContext(
+ '+',
+ $differ->getNew($j1, $j2),
+ $j2 === $newNoEolAtEofIdx
+ );
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Render the context array with the symbol.
+ *
+ * @param string $symbol the symbol
+ * @param string[] $context the context
+ * @param bool $noEolAtEof there is no EOL at EOF in this block
+ */
+ protected function renderContext(string $symbol, array $context, bool $noEolAtEof = false): string
+ {
+ if (empty($context)) {
+ return '';
+ }
+
+ $ret = $symbol . \implode("\n{$symbol}", $context) . "\n";
+ $ret = $this->cliColoredString($ret, $symbol);
+
+ if ($noEolAtEof) {
+ $ret .= self::GNU_OUTPUT_NO_EOL_AT_EOF . "\n";
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Utility/Arr.php b/vendor/jfcherng/php-diff/src/Utility/Arr.php
new file mode 100644
index 0000000..9283e30
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Utility/Arr.php
@@ -0,0 +1,47 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Utility;
+
+final class Arr
+{
+ /**
+ * Get a partial array slice with start/end indexes.
+ *
+ * @param array $array the array
+ * @param int $start the starting index (negative = count from backward)
+ * @param null|int $end the ending index (negative = count from backward)
+ * if is null, it returns a slice from $start to the end
+ *
+ * @return array array of all of the lines between the specified range
+ */
+ public static function getPartialByIndex(array $array, int $start = 0, ?int $end = null): array
+ {
+ $count = \count($array);
+
+ // make $end set
+ $end = $end ?? $count;
+
+ // make $start non-negative
+ if ($start < 0) {
+ $start += $count;
+
+ if ($start < 0) {
+ $start = 0;
+ }
+ }
+
+ // make $end non-negative
+ if ($end < 0) {
+ $end += $count;
+
+ if ($end < 0) {
+ $end = 0;
+ }
+ }
+
+ // make the length non-negative
+ return \array_slice($array, $start, \max(0, $end - $start));
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Utility/Language.php b/vendor/jfcherng/php-diff/src/Utility/Language.php
new file mode 100644
index 0000000..a2e531b
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Utility/Language.php
@@ -0,0 +1,137 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Utility;
+
+final class Language
+{
+ /**
+ * @var string[] the translation dict
+ */
+ private $translations = [];
+
+ /**
+ * @var string the language name
+ */
+ private $language = '_custom_';
+
+ /**
+ * The constructor.
+ *
+ * @param string|string[] $target the language string or translations dict
+ */
+ public function __construct($target = 'eng')
+ {
+ $this->setLanguageOrTranslations($target);
+ }
+
+ /**
+ * Set up this class.
+ *
+ * @param string|string[] $target the language string or translations array
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setLanguageOrTranslations($target): self
+ {
+ if (\is_string($target)) {
+ $this->setUpWithLanguage($target);
+
+ return $this;
+ }
+
+ if (\is_array($target)) {
+ $this->setUpWithTranslations($target);
+
+ return $this;
+ }
+
+ throw new \InvalidArgumentException('$target must be the type of string|string[]');
+ }
+
+ /**
+ * Get the language.
+ *
+ * @return string the language
+ */
+ public function getLanguage(): string
+ {
+ return $this->language;
+ }
+
+ /**
+ * Get the translations.
+ *
+ * @return array the translations
+ */
+ public function getTranslations(): array
+ {
+ return $this->translations;
+ }
+
+ /**
+ * Get the translations from the language file.
+ *
+ * @param string $language the language
+ *
+ * @throws \Exception fail to decode the JSON file
+ * @throws \LogicException path is a directory
+ * @throws \RuntimeException path cannot be opened
+ *
+ * @return string[]
+ */
+ public static function getTranslationsByLanguage(string $language): array
+ {
+ $filePath = __DIR__ . "/../languages/{$language}.json";
+ $file = new \SplFileObject($filePath, 'r');
+ $fileContent = $file->fread($file->getSize());
+
+ /** @todo PHP ^7.3 JSON_THROW_ON_ERROR */
+ $decoded = \json_decode($fileContent, true);
+
+ if (\json_last_error() !== \JSON_ERROR_NONE) {
+ $msg = \sprintf('Fail to decode JSON file (code %d): %s', \json_last_error(), \realpath($filePath));
+ throw new \Exception($msg); // workaround single-line throw + 120-char limit
+ }
+
+ return (array) $decoded;
+ }
+
+ /**
+ * Translation the text.
+ *
+ * @param string $text the text
+ */
+ public function translate(string $text): string
+ {
+ return $this->translations[$text] ?? "![{$text}]";
+ }
+
+ /**
+ * Set up this class by language name.
+ *
+ * @param string $language the language name
+ */
+ private function setUpWithLanguage(string $language): self
+ {
+ return $this->setUpWithTranslations(
+ self::getTranslationsByLanguage($language),
+ $language
+ );
+ }
+
+ /**
+ * Set up this class by translations.
+ *
+ * @param string[] $translations the translations dict
+ * @param string $language the language name
+ */
+ private function setUpWithTranslations(array $translations, string $language = '_custom_'): self
+ {
+ $this->language = $language;
+ $this->translations = \array_map('strval', $translations);
+
+ return $this;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Utility/ReverseIterator.php b/vendor/jfcherng/php-diff/src/Utility/ReverseIterator.php
new file mode 100644
index 0000000..e684ae1
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Utility/ReverseIterator.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Utility;
+
+final class ReverseIterator
+{
+ public const ITERATOR_GET_VALUE = 0;
+ public const ITERATOR_GET_KEY = 1 << 0;
+ public const ITERATOR_GET_BOTH = 1 << 1;
+
+ /**
+ * The constructor.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Iterate the array reversely.
+ *
+ * @param array $array the array
+ * @param int $flags the flags
+ */
+ public static function fromArray(array $array, int $flags = self::ITERATOR_GET_VALUE): \Generator
+ {
+ // iterate [key => value] pair
+ if ($flags & self::ITERATOR_GET_BOTH) {
+ for (\end($array); ($key = \key($array)) !== null; \prev($array)) {
+ yield $key => \current($array);
+ }
+
+ return;
+ }
+
+ // iterate only key
+ if ($flags & self::ITERATOR_GET_KEY) {
+ for (\end($array); ($key = \key($array)) !== null; \prev($array)) {
+ yield $key;
+ }
+
+ return;
+ }
+
+ // iterate only value
+ for (\end($array); \key($array) !== null; \prev($array)) {
+ yield \current($array);
+ }
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/Utility/Str.php b/vendor/jfcherng/php-diff/src/Utility/Str.php
new file mode 100644
index 0000000..c7478d4
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/Utility/Str.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff\Utility;
+
+final class Str
+{
+ /**
+ * Determine if a given string starts with a given substring.
+ *
+ * @param string $haystack the haystack
+ * @param string $needle the needle
+ */
+ public static function startsWith(string $haystack, string $needle): bool
+ {
+ return \substr($haystack, 0, \strlen($needle)) === $needle;
+ }
+
+ /**
+ * Determine if a given string ends with a given substring.
+ *
+ * @param string $haystack the haystack
+ * @param string $needle the needle
+ */
+ public static function endsWith(string $haystack, string $needle): bool
+ {
+ return \substr($haystack, -\strlen($needle)) === $needle;
+ }
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/bul.json b/vendor/jfcherng/php-diff/src/languages/bul.json
new file mode 100644
index 0000000..33beaba
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/bul.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Стара версия",
+ "new_version": "Нова версия",
+ "differences": "Разлики"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/chs.json b/vendor/jfcherng/php-diff/src/languages/chs.json
new file mode 100644
index 0000000..23cafd6
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/chs.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "旧版本",
+ "new_version": "新版本",
+ "differences": "差异"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/cht.json b/vendor/jfcherng/php-diff/src/languages/cht.json
new file mode 100644
index 0000000..6d5bbc8
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/cht.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "舊版本",
+ "new_version": "新版本",
+ "differences": "差異"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/deu.json b/vendor/jfcherng/php-diff/src/languages/deu.json
new file mode 100644
index 0000000..6627331
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/deu.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Alt",
+ "new_version": "Neu",
+ "differences": "Unterschiede"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/eng.json b/vendor/jfcherng/php-diff/src/languages/eng.json
new file mode 100644
index 0000000..8c180fc
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/eng.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Old",
+ "new_version": "New",
+ "differences": "Differences"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/fra.json b/vendor/jfcherng/php-diff/src/languages/fra.json
new file mode 100644
index 0000000..a56192d
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/fra.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Avant",
+ "new_version": "Après",
+ "differences": "Différences"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/ita.json b/vendor/jfcherng/php-diff/src/languages/ita.json
new file mode 100644
index 0000000..0432bab
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/ita.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Vecchio",
+ "new_version": "Nuovo",
+ "differences": "Differenze"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/jpn.json b/vendor/jfcherng/php-diff/src/languages/jpn.json
new file mode 100644
index 0000000..72d46f6
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/jpn.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "古い",
+ "new_version": "新しい",
+ "differences": "差異"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/por.json b/vendor/jfcherng/php-diff/src/languages/por.json
new file mode 100644
index 0000000..9c48b5d
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/por.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Original",
+ "new_version": "Nova",
+ "differences": "Diferenças"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/rus.json b/vendor/jfcherng/php-diff/src/languages/rus.json
new file mode 100644
index 0000000..2d7fc8b
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/rus.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Старая версия",
+ "new_version": "Новая версия",
+ "differences": "Различия"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/spa.json b/vendor/jfcherng/php-diff/src/languages/spa.json
new file mode 100644
index 0000000..ac26acd
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/spa.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Anterior",
+ "new_version": "Nuevo",
+ "differences": "Diferencias"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/tur.json b/vendor/jfcherng/php-diff/src/languages/tur.json
new file mode 100644
index 0000000..a9ea14f
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/tur.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Eski",
+ "new_version": "Yeni",
+ "differences": "Değişiklikler"
+}
diff --git a/vendor/jfcherng/php-diff/src/languages/ukr.json b/vendor/jfcherng/php-diff/src/languages/ukr.json
new file mode 100644
index 0000000..43584d2
--- /dev/null
+++ b/vendor/jfcherng/php-diff/src/languages/ukr.json
@@ -0,0 +1,5 @@
+{
+ "old_version": "Було",
+ "new_version": "Стало",
+ "differences": "Відмінності"
+}
diff --git a/vendor/jfcherng/php-mb-string/LICENSE b/vendor/jfcherng/php-mb-string/LICENSE
new file mode 100644
index 0000000..23e2091
--- /dev/null
+++ b/vendor/jfcherng/php-mb-string/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018-2022 Jack Cherng <jfcherng@gmail.com>
+
+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/jfcherng/php-mb-string/composer.json b/vendor/jfcherng/php-mb-string/composer.json
new file mode 100644
index 0000000..9041dba
--- /dev/null
+++ b/vendor/jfcherng/php-mb-string/composer.json
@@ -0,0 +1,50 @@
+{
+ "name": "jfcherng/php-mb-string",
+ "description": "A high performance multibytes sting implementation for frequently reading/writing operations.",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ }
+ ],
+ "minimum-stability": "beta",
+ "prefer-stable": true,
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Utility\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Jfcherng\\Utility\\Test\\": "tests/"
+ }
+ },
+ "config": {
+ "platform": {
+ "php": "7.1.3"
+ },
+ "sort-packages": true
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "ext-iconv": "*"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.18",
+ "phan/phan": "^2 || ^3 || ^4",
+ "phpunit/phpunit": "^7.2 || ^8 || ^9"
+ },
+ "scripts": {
+ "analyze": [
+ "phan --color"
+ ],
+ "fix": [
+ "php-cs-fixer fix --verbose"
+ ],
+ "test": [
+ "phpunit --verbose"
+ ]
+ }
+}
diff --git a/vendor/jfcherng/php-mb-string/src/MbString.php b/vendor/jfcherng/php-mb-string/src/MbString.php
new file mode 100644
index 0000000..afe7fdb
--- /dev/null
+++ b/vendor/jfcherng/php-mb-string/src/MbString.php
@@ -0,0 +1,367 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Utility;
+
+/**
+ * An internal UTF-32 multi-bytes string class.
+ *
+ * Because UTF-8 is varied-width, mb_*() is kinda O(n) when doing decoding.
+ * Using iconv() to make it UTF-32 and work with str*() can be possibly faster.
+ *
+ * UTF-32 is a fix-width encoding (1 char = 4 bytes).
+ * Note that the first 4 bytes in a UTF-32 string is the header (endian bytes).
+ *
+ * @author Jack Cherng <jfcherng@gmail.com>
+ */
+class MbString extends \ArrayObject
+{
+ /**
+ * UTF-32 string without endian bytes.
+ *
+ * @var string
+ */
+ protected $str;
+
+ /**
+ * The original encoding.
+ *
+ * @var string
+ */
+ protected $encoding;
+
+ /**
+ * The endian bytes for UTF-32.
+ *
+ * @var string
+ */
+ protected static $utf32Header;
+
+ /**
+ * The constructor.
+ *
+ * @param string $str the string
+ * @param string $encoding the encoding
+ */
+ public function __construct(string $str = '', string $encoding = 'UTF-8')
+ {
+ static::$utf32Header = static::$utf32Header ?? static::getUtf32Header();
+
+ $this->encoding = $encoding;
+ $this->set($str);
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return string string representation of the object
+ */
+ public function __toString(): string
+ {
+ return $this->get();
+ }
+
+ /**
+ * The string setter.
+ *
+ * @param string $str the string
+ */
+ public function set(string $str): self
+ {
+ $this->str = $this->inputConv($str);
+
+ return $this;
+ }
+
+ public function setAt(int $idx, string $char): self
+ {
+ $char = $this->inputConv($char);
+ if (\strlen($char) > 4) {
+ $char = \substr($char, 0, 4);
+ }
+
+ $spacesPrepend = $idx - $this->strlen();
+ // set index (out of bound)
+ if ($spacesPrepend > 0) {
+ $this->str .= $this->inputConv(\str_repeat(' ', $spacesPrepend)) . $char;
+ }
+ // set index (in bound)
+ else {
+ $this->str = \substr_replace($this->str, $char, $idx << 2, 4);
+ }
+
+ return $this;
+ }
+
+ /**
+ * The string getter.
+ */
+ public function get(): string
+ {
+ return $this->outputConv($this->str);
+ }
+
+ /**
+ * The raw string getter.
+ *
+ * @return string the UTF-32-encoded raw string
+ */
+ public function getRaw(): string
+ {
+ return $this->str;
+ }
+
+ public function getAt(int $idx): string
+ {
+ return $this->outputConv(\substr($this->str, $idx << 2, 4));
+ }
+
+ public function getAtRaw(int $idx): string
+ {
+ return \substr($this->str, $idx << 2, 4);
+ }
+
+ public function toArray(): array
+ {
+ return self::strToChars($this->get());
+ }
+
+ public function toArraySplit(string $regex, int $limit = -1, $flags = 0): array
+ {
+ if ($this->str === '') {
+ return [];
+ }
+
+ return \preg_split($regex, $this->get(), $limit, $flags);
+ }
+
+ public function toArrayRaw(): array
+ {
+ if ($this->str === '') {
+ return [];
+ }
+
+ return \str_split($this->str, 4);
+ }
+
+ public static function strToChars(string $str): array
+ {
+ return \preg_match_all('/./suS', $str, $matches) ? $matches[0] : [];
+ }
+
+ ///////////////////////////////////
+ // string manipulation functions //
+ ///////////////////////////////////
+
+ public function stripos(string $needle, int $offset = 0)
+ {
+ $needle = $this->inputConv($needle);
+ $pos = \stripos($this->str, $needle, $offset << 2);
+
+ return \is_bool($pos) ? $pos : $pos >> 2;
+ }
+
+ public function strlen(): int
+ {
+ return \strlen($this->str) >> 2;
+ }
+
+ public function strpos(string $needle, int $offset = 0)
+ {
+ $needle = $this->inputConv($needle);
+ $pos = \strpos($this->str, $needle, $offset << 2);
+
+ return \is_bool($pos) ? $pos : $pos >> 2;
+ }
+
+ public function substr(int $start = 0, ?int $length = null): string
+ {
+ return $this->outputConv(
+ isset($length)
+ ? \substr($this->str, $start << 2, $length << 2)
+ : \substr($this->str, $start << 2)
+ );
+ }
+
+ public function substr_replace(string $replacement, int $start = 0, ?int $length = null): string
+ {
+ $replacement = $this->inputConv($replacement);
+
+ return $this->outputConv(
+ isset($length)
+ ? \substr_replace($this->str, $replacement, $start << 2, $length << 2)
+ : \substr_replace($this->str, $replacement, $start << 2)
+ );
+ }
+
+ public function strtolower(): string
+ {
+ return \strtolower($this->get());
+ }
+
+ public function strtoupper(): string
+ {
+ return \strtoupper($this->get());
+ }
+
+ ////////////////////////////////
+ // non-manipulative functions //
+ ////////////////////////////////
+
+ public function has(string $needle): bool
+ {
+ $needle = $this->inputConv($needle);
+
+ return \strpos($this->str, $needle) !== false;
+ }
+
+ public function startsWith(string $needle): bool
+ {
+ $needle = $this->inputConv($needle);
+
+ return $needle === \substr($this->str, 0, \strlen($needle));
+ }
+
+ public function endsWith(string $needle): bool
+ {
+ $needle = $this->inputConv($needle);
+ $length = \strlen($needle);
+
+ return $length === 0 ? true : $needle === \substr($this->str, -$length);
+ }
+
+ /////////////////////////////////////////////
+ // those functions will not return a value //
+ /////////////////////////////////////////////
+
+ public function str_insert_i(string $insert, int $position): self
+ {
+ $insert = $this->inputConv($insert);
+ $this->str = \substr_replace($this->str, $insert, $position << 2, 0);
+
+ return $this;
+ }
+
+ public function str_enclose_i(array $closures, int $start = 0, ?int $length = null): self
+ {
+ // ex: $closures = array('{', '}');
+ foreach ($closures as &$closure) {
+ $closure = $this->inputConv($closure);
+ }
+ unset($closure);
+
+ if (\count($closures) < 2) {
+ $closures[0] = $closures[1] = \reset($closures);
+ }
+
+ if (isset($length)) {
+ $replacement = $closures[0] . \substr($this->str, $start << 2, $length << 2) . $closures[1];
+ $this->str = \substr_replace($this->str, $replacement, $start << 2, $length << 2);
+ } else {
+ $replacement = $closures[0] . \substr($this->str, $start << 2) . $closures[1];
+ $this->str = \substr_replace($this->str, $replacement, $start << 2);
+ }
+
+ return $this;
+ }
+
+ public function str_replace_i(string $search, string $replace): self
+ {
+ $search = $this->inputConv($search);
+ $replace = $this->inputConv($replace);
+ $this->str = \str_replace($search, $replace, $this->str);
+
+ return $this;
+ }
+
+ public function substr_replace_i(string $replacement, int $start = 0, ?int $length = null): self
+ {
+ $replacement = $this->inputConv($replacement);
+ $this->str = (
+ isset($length)
+ ? \substr_replace($this->str, $replacement, $start << 2, $length << 2)
+ : \substr_replace($this->str, $replacement, $start << 2)
+ );
+
+ return $this;
+ }
+
+ /////////////////
+ // ArrayObject //
+ /////////////////
+
+ #[\ReturnTypeWillChange]
+ public function offsetSet($idx, $char): void
+ {
+ $this->setAt($idx, $char);
+ }
+
+ #[\ReturnTypeWillChange]
+ public function offsetGet($idx): string
+ {
+ return $this->getAt($idx);
+ }
+
+ #[\ReturnTypeWillChange]
+ public function offsetExists($idx): bool
+ {
+ return \is_int($idx) ? $this->strlen() > $idx : false;
+ }
+
+ #[\ReturnTypeWillChange]
+ public function append($str): void
+ {
+ $this->str .= $this->inputConv($str);
+ }
+
+ public function count(): int
+ {
+ return $this->strlen();
+ }
+
+ ////////////////////
+ // misc functions //
+ ////////////////////
+
+ /**
+ * Gets the utf 32 header.
+ *
+ * @return string the UTF-32 header or empty string
+ */
+ protected static function getUtf32Header(): string
+ {
+ // just use any string to get the endian header, here we use "A"
+ $tmp = \iconv('UTF-8', 'UTF-32', 'A');
+ // some distributions like "php alpine" docker image won't generate the header
+ return $tmp && \strlen($tmp) > 4 ? \substr($tmp, 0, 4) : '';
+ }
+
+ /**
+ * Convert the output string to its original encoding.
+ *
+ * @param string $str The string
+ */
+ protected function outputConv(string $str): string
+ {
+ if ($str === '') {
+ return '';
+ }
+
+ return \iconv('UTF-32', $this->encoding, static::$utf32Header . $str);
+ }
+
+ /**
+ * Convert the input string to UTF-32 without header.
+ *
+ * @param string $str The string
+ */
+ protected function inputConv(string $str): string
+ {
+ if ($str === '') {
+ return '';
+ }
+
+ return \substr(\iconv($this->encoding, 'UTF-32', $str), \strlen(static::$utf32Header));
+ }
+}
diff --git a/vendor/jfcherng/php-sequence-matcher/.php-cs-fixer.dist.php b/vendor/jfcherng/php-sequence-matcher/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..1878a60
--- /dev/null
+++ b/vendor/jfcherng/php-sequence-matcher/.php-cs-fixer.dist.php
@@ -0,0 +1,78 @@
+<?php
+
+$config = (new PhpCsFixer\Config())
+ ->setIndent(" ")
+ ->setLineEnding("\n")
+ ->setCacheFile(__DIR__ . '/.php-cs-fixer.cache')
+ ->setRiskyAllowed(true)
+ ->setRules([
+ '@PHP71Migration' => true,
+ '@PHP73Migration' => false,
+ '@PhpCsFixer' => true,
+ '@PhpCsFixer:risky' => true,
+ '@PSR12' => true,
+ '@Symfony' => true,
+ '@Symfony:risky' => true,
+ 'align_multiline_comment' => true,
+ 'array_indentation' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'combine_consecutive_issets' => true,
+ 'combine_consecutive_unsets' => true,
+ 'combine_nested_dirname' => true,
+ 'comment_to_phpdoc' => true,
+ 'compact_nullable_typehint' => true,
+ 'concat_space' => ['spacing' => 'one'],
+ 'escape_implicit_backslashes' => false,
+ 'fully_qualified_strict_types' => true,
+ 'linebreak_after_opening_tag' => true,
+ 'list_syntax' => ['syntax' => 'short'],
+ 'method_argument_space' => ['ensure_fully_multiline' => true],
+ 'native_constant_invocation' => true,
+ 'native_function_invocation' => true,
+ 'native_function_type_declaration_casing' => true,
+ 'no_alternative_syntax' => true,
+ 'no_multiline_whitespace_before_semicolons' => true,
+ 'no_null_property_initialization' => true,
+ 'no_short_echo_tag' => true,
+ 'no_superfluous_elseif' => true,
+ 'no_trailing_whitespace_in_string' => false, // test cases have trailing spaces
+ 'no_unneeded_control_parentheses' => true,
+ 'no_useless_else' => true,
+ 'no_useless_return' => true,
+ 'not_operator_with_space' => false,
+ 'not_operator_with_successor_space' => false,
+ 'ordered_class_elements' => true,
+ 'ordered_imports' => ['sort_algorithm' => 'alpha', 'imports_order' => ['class', 'const', 'function']],
+ 'ordered_interfaces' => true,
+ 'php_unit_ordered_covers' => true,
+ 'php_unit_set_up_tear_down_visibility' => true,
+ 'php_unit_strict' => true,
+ 'php_unit_test_class_requires_covers' => true,
+ 'phpdoc_add_missing_param_annotation' => true,
+ 'phpdoc_order' => true,
+ 'phpdoc_to_comment' => false,
+ 'phpdoc_types_order' => true,
+ 'pow_to_exponentiation' => true,
+ 'random_api_migration' => true,
+ 'return_assignment' => false,
+ 'simple_to_complex_string_variable' => true,
+ 'single_line_comment_style' => true,
+ 'single_trait_insert_per_statement' => true,
+ 'strict_comparison' => false,
+ 'strict_param' => false,
+ 'string_line_ending' => true,
+ 'yoda_style' => false,
+ ])
+ ->setFinder(
+ PhpCsFixer\Finder::create()
+ ->notPath('/branch-\\w+/') // git worktree
+ ->exclude('libs')
+ ->exclude('tests/data')
+ ->exclude('tests/Fixtures')
+ ->exclude('var')
+ ->exclude('vendor')
+ ->in(__DIR__)
+ )
+;
+
+return $config;
diff --git a/vendor/jfcherng/php-sequence-matcher/LICENSE b/vendor/jfcherng/php-sequence-matcher/LICENSE
new file mode 100644
index 0000000..635035c
--- /dev/null
+++ b/vendor/jfcherng/php-sequence-matcher/LICENSE
@@ -0,0 +1,31 @@
+BSD 3-Clause License
+
+Copyright (c) 2019-2020 Jack Cherng <jfcherng@gmail.com>
+Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
+
+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 copyright holder 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 HOLDER OR 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.
diff --git a/vendor/jfcherng/php-sequence-matcher/composer.json b/vendor/jfcherng/php-sequence-matcher/composer.json
new file mode 100644
index 0000000..1244801
--- /dev/null
+++ b/vendor/jfcherng/php-sequence-matcher/composer.json
@@ -0,0 +1,56 @@
+{
+ "name": "jfcherng/php-sequence-matcher",
+ "description": "A longest sequence matcher. The logic is primarily based on the Python difflib package.",
+ "type": "library",
+ "license": "BSD-3-Clause",
+ "minimum-stability": "beta",
+ "prefer-stable": true,
+ "authors": [
+ {
+ "name": "Jack Cherng",
+ "email": "jfcherng@gmail.com"
+ },
+ {
+ "name": "Chris Boulton",
+ "email": "chris.boulton@interspire.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Jfcherng\\Diff\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Jfcherng\\Diff\\Test\\": "tests/"
+ }
+ },
+ "require": {
+ "php": ">=7.1.3"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.19",
+ "liip/rmt": "^1.6",
+ "phan/phan": "^2.5 || ^3 || ^4 || ^5",
+ "phpunit/phpunit": ">=7 <10",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "config": {
+ "platform": {
+ "php": "7.1.3"
+ },
+ "sort-packages": true
+ },
+ "scripts": {
+ "analyze": [
+ "phan --color",
+ "phpcs --colors -n"
+ ],
+ "fix": [
+ "php-cs-fixer fix --verbose"
+ ],
+ "test": [
+ "phpunit --verbose"
+ ]
+ }
+}
diff --git a/vendor/jfcherng/php-sequence-matcher/src/SequenceMatcher.php b/vendor/jfcherng/php-sequence-matcher/src/SequenceMatcher.php
new file mode 100644
index 0000000..61b73c2
--- /dev/null
+++ b/vendor/jfcherng/php-sequence-matcher/src/SequenceMatcher.php
@@ -0,0 +1,721 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Jfcherng\Diff;
+
+/**
+ * A longest sequence matcher.
+ *
+ * The logic is primarily based on the Python difflib package.
+ *
+ * @see https://docs.python.org/3/library/difflib.html
+ */
+final class SequenceMatcher
+{
+ /** @var int 0, opcode: no operation */
+ const OP_NOP = 0;
+
+ /** @var int 1, opcode: equal */
+ const OP_EQ = 1 << 0;
+
+ /** @var int 2, opcode: delete */
+ const OP_DEL = 1 << 1;
+
+ /** @var int 4, opcode: insert */
+ const OP_INS = 1 << 2;
+
+ /** @var int 8, opcode: replace */
+ const OP_REP = 1 << 3;
+
+ const OP_INT_TO_STR_MAP = [
+ self::OP_NOP => 'nop',
+ self::OP_EQ => 'eq',
+ self::OP_DEL => 'del',
+ self::OP_INS => 'ins',
+ self::OP_REP => 'rep',
+ ];
+
+ const OP_STR_TO_INT_MAP = [
+ 'nop' => self::OP_NOP,
+ 'eq' => self::OP_EQ,
+ 'del' => self::OP_DEL,
+ 'ins' => self::OP_INS,
+ 'rep' => self::OP_REP,
+ ];
+
+ /**
+ * The helper line which may be used to append to the source inputs to help
+ * it easier to handle EOL at EOF problem. This line shouldn't be counted into diff.
+ *
+ * @var string
+ */
+ const APPENDED_HELPER_LINE = "\u{fcf28}\u{fc232}";
+
+ /**
+ * @var null|callable either a string or an array containing a callback function to determine if a line is "junk" or not
+ */
+ private $junkCallback;
+
+ /**
+ * @var array the first sequence to compare against
+ */
+ private $a = [];
+
+ /**
+ * @var array the second sequence
+ */
+ private $b = [];
+
+ /**
+ * @var array the first sequence to compare against (transformed)
+ */
+ private $at = [];
+
+ /**
+ * @var array the second sequence (transformed)
+ */
+ private $bt = [];
+
+ /**
+ * @var array array of characters that are considered junk from the second sequence. Characters are the array key.
+ */
+ private $junkDict = [];
+
+ /**
+ * @var array array of indices that do not contain junk elements
+ */
+ private $b2j = [];
+
+ /**
+ * @var array
+ */
+ private $options = [];
+
+ /**
+ * @var array
+ */
+ private static $defaultOptions = [
+ 'ignoreWhitespace' => false,
+ 'ignoreCase' => false,
+ ];
+
+ /**
+ * @var array
+ */
+ private $matchingBlocks = [];
+
+ /**
+ * @var array generated opcodes which manipulates seq1 to seq2
+ */
+ private $opcodes = [];
+
+ /**
+ * The constructor. With the sequences being passed, they'll be set
+ * for the sequence matcher and it will perform a basic cleanup &
+ * calculate junk elements.
+ *
+ * @param string[] $a an array containing the lines to compare against
+ * @param string[] $b an array containing the lines to compare
+ * @param null|callable $junkCallback either an array or string that references a callback function (if there is one) to determine 'junk' characters
+ * @param array $options the options
+ */
+ public function __construct(array $a, array $b, ?callable $junkCallback = null, array $options = [])
+ {
+ $this->junkCallback = $junkCallback;
+ $this->setOptions($options);
+ $this->setSequences($a, $b);
+ }
+
+ /**
+ * Set the options.
+ *
+ * @param array $options The options
+ */
+ public function setOptions(array $options): self
+ {
+ $needRerunChainB = $this->isAnyOptionChanged($this->options, $options, ['ignoreCase', 'ignoreWhitespace']);
+
+ $this->options = $options + self::$defaultOptions;
+
+ if ($needRerunChainB) {
+ $this->chainB();
+ }
+
+ $this->resetCachedResults();
+
+ return $this;
+ }
+
+ /**
+ * Get the options.
+ */
+ public function getOptions(): array
+ {
+ return $this->options;
+ }
+
+ /**
+ * Reset cached results.
+ */
+ public function resetCachedResults(): self
+ {
+ $this->matchingBlocks = [];
+ $this->opcodes = [];
+
+ return $this;
+ }
+
+ /**
+ * Set the first and second sequences to use with the sequence matcher.
+ *
+ * This method is more effecient than "->setSeq1($old)->setSeq2($new)"
+ * because it only run the routine once.
+ *
+ * @param string[] $a an array containing the lines to compare against
+ * @param string[] $b an array containing the lines to compare
+ */
+ public function setSequences(array $a, array $b): self
+ {
+ $need_routine = false;
+
+ if ($this->a !== $a) {
+ $need_routine = true;
+ $this->a = $a;
+ }
+
+ if ($this->b !== $b) {
+ $need_routine = true;
+ $this->b = $b;
+ }
+
+ if ($need_routine) {
+ $this->chainB();
+ $this->resetCachedResults();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the first sequence ($a) and reset any internal caches to indicate that
+ * when calling the calculation methods, we need to recalculate them.
+ *
+ * @param string[] $a the sequence to set as the first sequence
+ */
+ public function setSeq1(array $a): self
+ {
+ if ($this->a !== $a) {
+ $this->a = $a;
+ $this->chainB();
+ $this->resetCachedResults();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the second sequence ($b) and reset any internal caches to indicate that
+ * when calling the calculation methods, we need to recalculate them.
+ *
+ * @param string[] $b the sequence to set as the second sequence
+ */
+ public function setSeq2(array $b): self
+ {
+ if ($this->b !== $b) {
+ $this->b = $b;
+ $this->chainB();
+ $this->resetCachedResults();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Find the longest matching block in the two sequences, as defined by the
+ * lower and upper constraints for each sequence. (for the first sequence,
+ * $alo - $ahi and for the second sequence, $blo - $bhi).
+ *
+ * Essentially, of all of the maximal matching blocks, return the one that
+ * startest earliest in $a, and all of those maximal matching blocks that
+ * start earliest in $a, return the one that starts earliest in $b.
+ *
+ * If the junk callback is defined, do the above but with the restriction
+ * that the junk element appears in the block. Extend it as far as possible
+ * by matching only junk elements in both $a and $b.
+ *
+ * @param int $alo the lower constraint for the first sequence
+ * @param int $ahi the upper constraint for the first sequence
+ * @param int $blo the lower constraint for the second sequence
+ * @param int $bhi the upper constraint for the second sequence
+ *
+ * @return int[] an array containing the longest match that includes the starting position in $a, start in $b and the length/size
+ */
+ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array
+ {
+ $bestI = $alo;
+ $bestJ = $blo;
+ $bestSize = 0;
+
+ $j2Len = [];
+
+ for ($i = $alo; $i < $ahi; ++$i) {
+ if (null === ($element = $this->at[$i] ?? null)) {
+ continue;
+ }
+
+ $newJ2Len = [];
+ $jDict = $this->b2j[$element] ?? [];
+
+ foreach ($jDict as $j) {
+ if ($j < $blo) {
+ continue;
+ }
+
+ if ($j >= $bhi) {
+ break;
+ }
+
+ $k = ($j2Len[$j - 1] ?? 0) + 1;
+ $newJ2Len[$j] = $k;
+
+ if ($k > $bestSize) {
+ $bestI = $i - $k + 1;
+ $bestJ = $j - $k + 1;
+ $bestSize = $k;
+ }
+ }
+
+ $j2Len = $newJ2Len;
+ }
+
+ while (
+ $bestI > $alo
+ && $bestJ > $blo
+ && $this->at[$bestI - 1] === $this->bt[$bestJ - 1]
+ && !$this->isBJunk($this->bt[$bestJ - 1])
+ ) {
+ --$bestI;
+ --$bestJ;
+ ++$bestSize;
+ }
+
+ while (
+ $bestI + $bestSize < $ahi
+ && $bestJ + $bestSize < $bhi
+ && $this->at[$bestI + $bestSize] === $this->bt[$bestJ + $bestSize]
+ && !$this->isBJunk($this->bt[$bestJ + $bestSize])
+ ) {
+ ++$bestSize;
+ }
+
+ while (
+ $bestI > $alo
+ && $bestJ > $blo
+ && $this->at[$bestI - 1] === $this->bt[$bestJ - 1]
+ && $this->isBJunk($this->bt[$bestJ - 1])
+ ) {
+ --$bestI;
+ --$bestJ;
+ ++$bestSize;
+ }
+
+ while (
+ $bestI + $bestSize < $ahi
+ && $bestJ + $bestSize < $bhi
+ && $this->at[$bestI + $bestSize] === $this->bt[$bestJ + $bestSize]
+ && $this->isBJunk($this->bt[$bestJ + $bestSize])
+ ) {
+ ++$bestSize;
+ }
+
+ return [$bestI, $bestJ, $bestSize];
+ }
+
+ /**
+ * Return a nested set of arrays for all of the matching sub-sequences
+ * in the strings $a and $b.
+ *
+ * Each block contains the lower constraint of the block in $a, the lower
+ * constraint of the block in $b and finally the number of lines that the
+ * block continues for.
+ *
+ * @return int[][] a nested array of the matching blocks, as described by the function
+ */
+ public function getMatchingBlocks(): array
+ {
+ if (!empty($this->matchingBlocks)) {
+ return $this->matchingBlocks;
+ }
+
+ $aCount = \count($this->a);
+ $bCount = \count($this->b);
+
+ $queue = [
+ [0, $aCount, 0, $bCount],
+ ];
+
+ $matchingBlocks = [];
+ while (!empty($queue)) {
+ [$alo, $ahi, $blo, $bhi] = \array_pop($queue);
+ [$i, $j, $k] = $x = $this->findLongestMatch($alo, $ahi, $blo, $bhi);
+
+ if ($k) {
+ $matchingBlocks[] = $x;
+
+ if ($alo < $i && $blo < $j) {
+ $queue[] = [$alo, $i, $blo, $j];
+ }
+
+ if ($i + $k < $ahi && $j + $k < $bhi) {
+ $queue[] = [$i + $k, $ahi, $j + $k, $bhi];
+ }
+ }
+ }
+
+ \usort($matchingBlocks, function (array $a, array $b): int {
+ $aCount = \count($a);
+ $bCount = \count($b);
+ $min = \min($aCount, $bCount);
+
+ for ($i = 0; $i < $min; ++$i) {
+ if ($a[$i] !== $b[$i]) {
+ return $a[$i] <=> $b[$i];
+ }
+ }
+
+ return $aCount <=> $bCount;
+ });
+
+ $i1 = $j1 = $k1 = 0;
+ $nonAdjacent = [];
+ foreach ($matchingBlocks as [$i2, $j2, $k2]) {
+ if ($i1 + $k1 === $i2 && $j1 + $k1 === $j2) {
+ $k1 += $k2;
+
+ continue;
+ }
+
+ if ($k1) {
+ $nonAdjacent[] = [$i1, $j1, $k1];
+ }
+
+ $i1 = $i2;
+ $j1 = $j2;
+ $k1 = $k2;
+ }
+
+ if ($k1) {
+ $nonAdjacent[] = [$i1, $j1, $k1];
+ }
+
+ $nonAdjacent[] = [$aCount, $bCount, 0];
+
+ $this->matchingBlocks = $nonAdjacent;
+
+ return $this->matchingBlocks;
+ }
+
+ /**
+ * Return a list of all of the opcodes for the differences between the
+ * two strings.
+ *
+ * The nested array returned contains an array describing the opcode
+ * which includes:
+ * 0 - The type of tag (as described below) for the opcode.
+ * 1 - The beginning line in the first sequence.
+ * 2 - The end line in the first sequence.
+ * 3 - The beginning line in the second sequence.
+ * 4 - The end line in the second sequence.
+ *
+ * The different types of tags include:
+ * replace - The string from $i1 to $i2 in $a should be replaced by
+ * the string in $b from $j1 to $j2.
+ * delete - The string in $a from $i1 to $j2 should be deleted.
+ * insert - The string in $b from $j1 to $j2 should be inserted at
+ * $i1 in $a.
+ * equal - The two strings with the specified ranges are equal.
+ *
+ * @return int[][] array of the opcodes describing the differences between the strings
+ */
+ public function getOpcodes(): array
+ {
+ if (!empty($this->opcodes)) {
+ return $this->opcodes;
+ }
+
+ $i = $j = 0;
+ $this->opcodes = [];
+
+ foreach ($this->getMatchingBlocks() as [$ai, $bj, $size]) {
+ if ($i < $ai && $j < $bj) {
+ $tag = self::OP_REP;
+ } elseif ($i < $ai) {
+ $tag = self::OP_DEL;
+ } elseif ($j < $bj) {
+ $tag = self::OP_INS;
+ } else {
+ $tag = self::OP_NOP;
+ }
+
+ if ($tag) {
+ $this->opcodes[] = [$tag, $i, $ai, $j, $bj];
+ }
+
+ $i = $ai + $size;
+ $j = $bj + $size;
+
+ if ($size) {
+ $this->opcodes[] = [self::OP_EQ, $ai, $i, $bj, $j];
+ }
+ }
+
+ return $this->opcodes;
+ }
+
+ /**
+ * Return a series of nested arrays containing different groups of generated
+ * opcodes for the differences between the strings with up to $context lines
+ * of surrounding content.
+ *
+ * Essentially what happens here is any big equal blocks of strings are stripped
+ * out, the smaller subsets of changes are then arranged in to their groups.
+ * This means that the sequence matcher and diffs do not need to include the full
+ * content of the different files but can still provide context as to where the
+ * changes are.
+ *
+ * @param int $context the number of lines of context to provide around the groups
+ *
+ * @return int[][][] nested array of all of the grouped opcodes
+ */
+ public function getGroupedOpcodes(int $context = 3): array
+ {
+ $opcodes = $this->getOpcodes();
+
+ if (empty($opcodes)) {
+ $opcodes = [
+ [self::OP_EQ, 0, 1, 0, 1],
+ ];
+ }
+
+ if ($opcodes[0][0] === self::OP_EQ) {
+ // fix the leading sequence which is out of context.
+ $opcodes[0] = [
+ $opcodes[0][0],
+ \max($opcodes[0][1], $opcodes[0][2] - $context),
+ $opcodes[0][2],
+ \max($opcodes[0][3], $opcodes[0][4] - $context),
+ $opcodes[0][4],
+ ];
+ }
+
+ $lastItem = \count($opcodes) - 1;
+ if ($opcodes[$lastItem][0] === self::OP_EQ) {
+ [$tag, $i1, $i2, $j1, $j2] = $opcodes[$lastItem];
+ // fix the trailing sequence which is out of context.
+ $opcodes[$lastItem] = [
+ $tag,
+ $i1,
+ \min($i2, $i1 + $context),
+ $j1,
+ \min($j2, $j1 + $context),
+ ];
+ }
+
+ $maxRange = $context << 1;
+ $groups = $group = [];
+ foreach ($opcodes as [$tag, $i1, $i2, $j1, $j2]) {
+ if ($tag === self::OP_EQ && $i2 - $i1 > $maxRange) {
+ $group[] = [
+ $tag,
+ $i1,
+ \min($i2, $i1 + $context),
+ $j1,
+ \min($j2, $j1 + $context),
+ ];
+ $groups[] = $group;
+ $group = [];
+ $i1 = \max($i1, $i2 - $context);
+ $j1 = \max($j1, $j2 - $context);
+ }
+
+ $group[] = [$tag, $i1, $i2, $j1, $j2];
+ }
+
+ if (
+ !empty($group)
+ && (
+ \count($group) !== 1
+ || $group[0][0] !== self::OP_EQ
+ )
+ ) {
+ $groups[] = $group;
+ }
+
+ // there will be at least leading/trailing OP_EQ blocks
+ // if we want really zero-context, we keep only non-equal blocks
+ if ($context <= 0) {
+ $groupsNew = [];
+
+ foreach ($groups as $group) {
+ $groupNew = [];
+
+ foreach ($group as $block) {
+ if ($block[0] !== self::OP_EQ) {
+ $groupNew[] = $block;
+ }
+ }
+
+ if (!empty($groupNew)) {
+ $groupsNew[] = $groupNew;
+ }
+ }
+
+ return $groupsNew;
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Convert an operation code from int into its string form.
+ *
+ * @param int $op the operation code
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return string the string representation of the operation code
+ */
+ public static function opIntToStr(int $op): string
+ {
+ if (!isset(self::OP_INT_TO_STR_MAP[$op])) {
+ throw new \InvalidArgumentException("Invalid OP: {$op}");
+ }
+
+ return self::OP_INT_TO_STR_MAP[$op];
+ }
+
+ /**
+ * Convert an operation code from string into its int form.
+ *
+ * @param string $op the operation code
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return int the int representation of the operation code
+ */
+ public static function opStrToInt(string $op): int
+ {
+ if (!isset(self::OP_STR_TO_INT_MAP[$op])) {
+ throw new \InvalidArgumentException("Invalid OP: {$op}");
+ }
+
+ return self::OP_STR_TO_INT_MAP[$op];
+ }
+
+ /**
+ * Determine if any option under test changed.
+ *
+ * @param array $old the old options
+ * @param array $new the new options
+ * @param array $keys the option keys under test
+ */
+ private function isAnyOptionChanged(array $old, array $new, array $keys): bool
+ {
+ foreach ($keys as $key) {
+ if (isset($new[$key]) && $new[$key] !== $old[$key]) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the processed line with the initialized options.
+ *
+ * @param string $line the line
+ *
+ * @return string the line after being processed
+ */
+ private function processLineWithOptions(string $line): string
+ {
+ if ($this->options['ignoreWhitespace']) {
+ static $whitespaces = [' ', "\t", "\r", "\n"];
+
+ $line = \str_replace($whitespaces, '', $line);
+ }
+
+ if ($this->options['ignoreCase']) {
+ $line = \strtolower($line);
+ }
+
+ return $line;
+ }
+
+ /**
+ * Generate the internal arrays containing the list of junk and non-junk
+ * characters for the second ($b) sequence.
+ */
+ private function chainB(): self
+ {
+ $this->at = \array_map([$this, 'processLineWithOptions'], $this->a);
+ $this->bt = \array_map([$this, 'processLineWithOptions'], $this->b);
+
+ $length = \count($this->bt);
+ $this->b2j = [];
+ $popularDict = [];
+
+ for ($i = 0; $i < $length; ++$i) {
+ $char = $this->bt[$i];
+ $this->b2j[$char] = $this->b2j[$char] ?? [];
+
+ if (
+ $length >= 1000
+ && \count($this->b2j[$char]) * 100 > $length
+ && $char !== self::APPENDED_HELPER_LINE
+ ) {
+ $popularDict[$char] = 1;
+
+ unset($this->b2j[$char]);
+ } else {
+ $this->b2j[$char][] = $i;
+ }
+ }
+
+ // remove leftovers
+ foreach (\array_keys($popularDict) as $char) {
+ unset($this->b2j[$char]);
+ }
+
+ $this->junkDict = [];
+ if (\is_callable($this->junkCallback)) {
+ foreach (\array_keys($popularDict) as $char) {
+ if (($this->junkCallback)($char)) {
+ $this->junkDict[$char] = 1;
+ unset($popularDict[$char]);
+ }
+ }
+
+ foreach (\array_keys($this->b2j) as $char) {
+ if (($this->junkCallback)($char)) {
+ $this->junkDict[$char] = 1;
+ unset($this->b2j[$char]);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Checks if a particular character is in the junk dictionary
+ * for the list of junk characters.
+ *
+ * @return bool $b True if the character is considered junk. False if not.
+ */
+ private function isBJunk(string $b): bool
+ {
+ return isset($this->junkDict[$b]);
+ }
+}
diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE
new file mode 100644
index 0000000..45c7017
--- /dev/null
+++ b/vendor/paragonie/random_compat/LICENSE
@@ -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
index 0000000..f2b9c4e
--- /dev/null
+++ b/vendor/paragonie/random_compat/composer.json
@@ -0,0 +1,34 @@
+{
+ "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": ">= 7"
+ },
+ "require-dev": {
+ "vimeo/psalm": "^1",
+ "phpunit/phpunit": "4.*|5.*"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ }
+}
diff --git a/vendor/paragonie/random_compat/lib/random.php b/vendor/paragonie/random_compat/lib/random.php
new file mode 100644
index 0000000..c7731a5
--- /dev/null
+++ b/vendor/paragonie/random_compat/lib/random.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Random_* Compatibility Library
+ * for using the new PHP 7 random_* API in PHP 5 projects
+ *
+ * @version 2.99.99
+ * @released 2018-06-06
+ *
+ * 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.
+ */
+
+// NOP
diff --git a/vendor/paragonie/random_compat/other/build_phar.php b/vendor/paragonie/random_compat/other/build_phar.php
new file mode 100644
index 0000000..70ef4b2
--- /dev/null
+++ b/vendor/paragonie/random_compat/other/build_phar.php
@@ -0,0 +1,57 @@
+<?php
+$dist = dirname(__DIR__).'/dist';
+if (!is_dir($dist)) {
+ mkdir($dist, 0755);
+}
+if (file_exists($dist.'/random_compat.phar')) {
+ unlink($dist.'/random_compat.phar');
+}
+$phar = new Phar(
+ $dist.'/random_compat.phar',
+ FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_FILENAME,
+ 'random_compat.phar'
+);
+rename(
+ dirname(__DIR__).'/lib/random.php',
+ dirname(__DIR__).'/lib/index.php'
+);
+$phar->buildFromDirectory(dirname(__DIR__).'/lib');
+rename(
+ dirname(__DIR__).'/lib/index.php',
+ dirname(__DIR__).'/lib/random.php'
+);
+
+/**
+ * If we pass an (optional) path to a private key as a second argument, we will
+ * sign the Phar with OpenSSL.
+ *
+ * If you leave this out, it will produce an unsigned .phar!
+ */
+if ($argc > 1) {
+ if (!@is_readable($argv[1])) {
+ echo 'Could not read the private key file:', $argv[1], "\n";
+ exit(255);
+ }
+ $pkeyFile = file_get_contents($argv[1]);
+
+ $private = openssl_get_privatekey($pkeyFile);
+ if ($private !== false) {
+ $pkey = '';
+ openssl_pkey_export($private, $pkey);
+ $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
+
+ /**
+ * Save the corresponding public key to the file
+ */
+ if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
+ $details = openssl_pkey_get_details($private);
+ file_put_contents(
+ $dist.'/random_compat.phar.pubkey',
+ $details['key']
+ );
+ }
+ } else {
+ echo 'An error occurred reading the private key from OpenSSL.', "\n";
+ exit(255);
+ }
+}
diff --git a/vendor/paragonie/random_compat/psalm-autoload.php b/vendor/paragonie/random_compat/psalm-autoload.php
new file mode 100644
index 0000000..d71d1b8
--- /dev/null
+++ b/vendor/paragonie/random_compat/psalm-autoload.php
@@ -0,0 +1,9 @@
+<?php
+
+require_once 'lib/byte_safe_strings.php';
+require_once 'lib/cast_to_int.php';
+require_once 'lib/error_polyfill.php';
+require_once 'other/ide_stubs/libsodium.php';
+require_once 'lib/random.php';
+
+$int = random_int(0, 65536);
diff --git a/vendor/predis/predis/LICENSE b/vendor/predis/predis/LICENSE
new file mode 100644
index 0000000..c35b657
--- /dev/null
+++ b/vendor/predis/predis/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2009-2016 Daniele Alessandri
+
+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/predis/predis/autoload.php b/vendor/predis/predis/autoload.php
new file mode 100644
index 0000000..6b5a00b
--- /dev/null
+++ b/vendor/predis/predis/autoload.php
@@ -0,0 +1,14 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require __DIR__.'/src/Autoloader.php';
+
+Predis\Autoloader::register();
diff --git a/vendor/predis/predis/composer.json b/vendor/predis/predis/composer.json
new file mode 100644
index 0000000..bde0b54
--- /dev/null
+++ b/vendor/predis/predis/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "predis/predis",
+ "type": "library",
+ "description": "Flexible and feature-complete Redis client for PHP and HHVM",
+ "keywords": ["nosql", "redis", "predis"],
+ "homepage": "http://github.com/predis/predis",
+ "license": "MIT",
+ "support": {
+ "issues": "https://github.com/predis/predis/issues"
+ },
+ "authors": [
+ {
+ "name": "Daniele Alessandri",
+ "email": "suppakilla@gmail.com",
+ "homepage": "http://clorophilla.net",
+ "role": "Creator & Maintainer"
+ },
+ {
+ "name": "Till Krüss",
+ "homepage": "https://till.im",
+ "role": "Maintainer"
+ }
+ ],
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/tillkruss"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "suggest": {
+ "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
+ "ext-curl": "Allows access to Webdis when paired with phpiredis"
+ },
+ "autoload": {
+ "psr-4": {
+ "Predis\\": "src/"
+ }
+ },
+ "scripts": {
+ "post-update-cmd": "@php -f tests/apply-patches.php"
+ }
+}
diff --git a/vendor/predis/predis/src/Autoloader.php b/vendor/predis/predis/src/Autoloader.php
new file mode 100644
index 0000000..17ec2ff
--- /dev/null
+++ b/vendor/predis/predis/src/Autoloader.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+/**
+ * Implements a lightweight PSR-0 compliant autoloader for Predis.
+ *
+ * @author Eric Naeseth <eric@thumbtack.com>
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Autoloader
+{
+ private $directory;
+ private $prefix;
+ private $prefixLength;
+
+ /**
+ * @param string $baseDirectory Base directory where the source files are located.
+ */
+ public function __construct($baseDirectory = __DIR__)
+ {
+ $this->directory = $baseDirectory;
+ $this->prefix = __NAMESPACE__.'\\';
+ $this->prefixLength = strlen($this->prefix);
+ }
+
+ /**
+ * Registers the autoloader class with the PHP SPL autoloader.
+ *
+ * @param bool $prepend Prepend the autoloader on the stack instead of appending it.
+ */
+ public static function register($prepend = false)
+ {
+ spl_autoload_register(array(new self(), 'autoload'), true, $prepend);
+ }
+
+ /**
+ * Loads a class from a file using its fully qualified name.
+ *
+ * @param string $className Fully qualified name of a class.
+ */
+ public function autoload($className)
+ {
+ if (0 === strpos($className, $this->prefix)) {
+ $parts = explode('\\', substr($className, $this->prefixLength));
+ $filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
+
+ if (is_file($filepath)) {
+ require $filepath;
+ }
+ }
+ }
+}
diff --git a/vendor/predis/predis/src/Client.php b/vendor/predis/predis/src/Client.php
new file mode 100644
index 0000000..3538272
--- /dev/null
+++ b/vendor/predis/predis/src/Client.php
@@ -0,0 +1,550 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+use Predis\Command\CommandInterface;
+use Predis\Command\RawCommand;
+use Predis\Command\ScriptCommand;
+use Predis\Configuration\Options;
+use Predis\Configuration\OptionsInterface;
+use Predis\Connection\AggregateConnectionInterface;
+use Predis\Connection\ConnectionInterface;
+use Predis\Connection\ParametersInterface;
+use Predis\Monitor\Consumer as MonitorConsumer;
+use Predis\Pipeline\Pipeline;
+use Predis\PubSub\Consumer as PubSubConsumer;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\ResponseInterface;
+use Predis\Response\ServerException;
+use Predis\Transaction\MultiExec as MultiExecTransaction;
+
+/**
+ * Client class used for connecting and executing commands on Redis.
+ *
+ * This is the main high-level abstraction of Predis upon which various other
+ * abstractions are built. Internally it aggregates various other classes each
+ * one with its own responsibility and scope.
+ *
+ * {@inheritdoc}
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Client implements ClientInterface, \IteratorAggregate
+{
+ const VERSION = '1.1.10';
+
+ protected $connection;
+ protected $options;
+ private $profile;
+
+ /**
+ * @param mixed $parameters Connection parameters for one or more servers.
+ * @param mixed $options Options to configure some behaviours of the client.
+ */
+ public function __construct($parameters = null, $options = null)
+ {
+ $this->options = $this->createOptions($options ?: array());
+ $this->connection = $this->createConnection($parameters ?: array());
+ $this->profile = $this->options->profile;
+ }
+
+ /**
+ * Creates a new instance of Predis\Configuration\Options from different
+ * types of arguments or simply returns the passed argument if it is an
+ * instance of Predis\Configuration\OptionsInterface.
+ *
+ * @param mixed $options Client options.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return OptionsInterface
+ */
+ protected function createOptions($options)
+ {
+ if (is_array($options)) {
+ return new Options($options);
+ }
+
+ if ($options instanceof OptionsInterface) {
+ return $options;
+ }
+
+ throw new \InvalidArgumentException('Invalid type for client options.');
+ }
+
+ /**
+ * Creates single or aggregate connections from different types of arguments
+ * (string, array) or returns the passed argument if it is an instance of a
+ * class implementing Predis\Connection\ConnectionInterface.
+ *
+ * Accepted types for connection parameters are:
+ *
+ * - Instance of Predis\Connection\ConnectionInterface.
+ * - Instance of Predis\Connection\ParametersInterface.
+ * - Array
+ * - String
+ * - Callable
+ *
+ * @param mixed $parameters Connection parameters or connection instance.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return ConnectionInterface
+ */
+ protected function createConnection($parameters)
+ {
+ if ($parameters instanceof ConnectionInterface) {
+ return $parameters;
+ }
+
+ if ($parameters instanceof ParametersInterface || is_string($parameters)) {
+ return $this->options->connections->create($parameters);
+ }
+
+ if (is_array($parameters)) {
+ if (!isset($parameters[0])) {
+ return $this->options->connections->create($parameters);
+ }
+
+ $options = $this->options;
+
+ if ($options->defined('aggregate')) {
+ $initializer = $this->getConnectionInitializerWrapper($options->aggregate);
+ $connection = $initializer($parameters, $options);
+ } elseif ($options->defined('replication')) {
+ $replication = $options->replication;
+
+ if ($replication instanceof AggregateConnectionInterface) {
+ $connection = $replication;
+ $options->connections->aggregate($connection, $parameters);
+ } else {
+ $initializer = $this->getConnectionInitializerWrapper($replication);
+ $connection = $initializer($parameters, $options);
+ }
+ } else {
+ $connection = $options->cluster;
+ $options->connections->aggregate($connection, $parameters);
+ }
+
+ return $connection;
+ }
+
+ if (is_callable($parameters)) {
+ $initializer = $this->getConnectionInitializerWrapper($parameters);
+ $connection = $initializer($this->options);
+
+ return $connection;
+ }
+
+ throw new \InvalidArgumentException('Invalid type for connection parameters.');
+ }
+
+ /**
+ * Wraps a callable to make sure that its returned value represents a valid
+ * connection type.
+ *
+ * @param mixed $callable
+ *
+ * @return \Closure
+ */
+ protected function getConnectionInitializerWrapper($callable)
+ {
+ return function () use ($callable) {
+ $connection = call_user_func_array($callable, func_get_args());
+
+ if (!$connection instanceof ConnectionInterface) {
+ throw new \UnexpectedValueException(
+ 'The callable connection initializer returned an invalid type.'
+ );
+ }
+
+ return $connection;
+ };
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProfile()
+ {
+ return $this->profile;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Creates a new client instance for the specified connection ID or alias,
+ * only when working with an aggregate connection (cluster, replication).
+ * The new client instances uses the same options of the original one.
+ *
+ * @param string $connectionID Identifier of a connection.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return Client
+ */
+ public function getClientFor($connectionID)
+ {
+ if (!$connection = $this->getConnectionById($connectionID)) {
+ throw new \InvalidArgumentException("Invalid connection ID: $connectionID.");
+ }
+
+ return new static($connection, $this->options);
+ }
+
+ /**
+ * Opens the underlying connection and connects to the server.
+ */
+ public function connect()
+ {
+ $this->connection->connect();
+ }
+
+ /**
+ * Closes the underlying connection and disconnects from the server.
+ */
+ public function disconnect()
+ {
+ $this->connection->disconnect();
+ }
+
+ /**
+ * Closes the underlying connection and disconnects from the server.
+ *
+ * This is the same as `Client::disconnect()` as it does not actually send
+ * the `QUIT` command to Redis, but simply closes the connection.
+ */
+ public function quit()
+ {
+ $this->disconnect();
+ }
+
+ /**
+ * Returns the current state of the underlying connection.
+ *
+ * @return bool
+ */
+ public function isConnected()
+ {
+ return $this->connection->isConnected();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnection()
+ {
+ return $this->connection;
+ }
+
+ /**
+ * Retrieves the specified connection from the aggregate connection when the
+ * client is in cluster or replication mode.
+ *
+ * @param string $connectionID Index or alias of the single connection.
+ *
+ * @throws NotSupportedException
+ *
+ * @return Connection\NodeConnectionInterface
+ */
+ public function getConnectionById($connectionID)
+ {
+ if (!$this->connection instanceof AggregateConnectionInterface) {
+ throw new NotSupportedException(
+ 'Retrieving connections by ID is supported only by aggregate connections.'
+ );
+ }
+
+ return $this->connection->getConnectionById($connectionID);
+ }
+
+ /**
+ * Executes a command without filtering its arguments, parsing the response,
+ * applying any prefix to keys or throwing exceptions on Redis errors even
+ * regardless of client options.
+ *
+ * It is possible to identify Redis error responses from normal responses
+ * using the second optional argument which is populated by reference.
+ *
+ * @param array $arguments Command arguments as defined by the command signature.
+ * @param bool $error Set to TRUE when Redis returned an error response.
+ *
+ * @return mixed
+ */
+ public function executeRaw(array $arguments, &$error = null)
+ {
+ $error = false;
+
+ $response = $this->connection->executeCommand(
+ new RawCommand($arguments)
+ );
+
+ if ($response instanceof ResponseInterface) {
+ if ($response instanceof ErrorResponseInterface) {
+ $error = true;
+ }
+
+ return (string) $response;
+ }
+
+ return $response;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __call($commandID, $arguments)
+ {
+ return $this->executeCommand(
+ $this->createCommand($commandID, $arguments)
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createCommand($commandID, $arguments = array())
+ {
+ return $this->profile->createCommand($commandID, $arguments);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $response = $this->connection->executeCommand($command);
+
+ if ($response instanceof ResponseInterface) {
+ if ($response instanceof ErrorResponseInterface) {
+ $response = $this->onErrorResponse($command, $response);
+ }
+
+ return $response;
+ }
+
+ return $command->parseResponse($response);
+ }
+
+ /**
+ * Handles -ERR responses returned by Redis.
+ *
+ * @param CommandInterface $command Redis command that generated the error.
+ * @param ErrorResponseInterface $response Instance of the error response.
+ *
+ * @throws ServerException
+ *
+ * @return mixed
+ */
+ protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $response)
+ {
+ if ($command instanceof ScriptCommand && $response->getErrorType() === 'NOSCRIPT') {
+ $eval = $this->createCommand('EVAL');
+ $eval->setRawArguments($command->getEvalArguments());
+
+ $response = $this->executeCommand($eval);
+
+ if (!$response instanceof ResponseInterface) {
+ $response = $command->parseResponse($response);
+ }
+
+ return $response;
+ }
+
+ if ($this->options->exceptions) {
+ throw new ServerException($response->getMessage());
+ }
+
+ return $response;
+ }
+
+ /**
+ * Executes the specified initializer method on `$this` by adjusting the
+ * actual invokation depending on the arity (0, 1 or 2 arguments). This is
+ * simply an utility method to create Redis contexts instances since they
+ * follow a common initialization path.
+ *
+ * @param string $initializer Method name.
+ * @param array $argv Arguments for the method.
+ *
+ * @return mixed
+ */
+ private function sharedContextFactory($initializer, $argv = null)
+ {
+ switch (count($argv)) {
+ case 0:
+ return $this->$initializer();
+
+ case 1:
+ return is_array($argv[0])
+ ? $this->$initializer($argv[0])
+ : $this->$initializer(null, $argv[0]);
+
+ case 2:
+ list($arg0, $arg1) = $argv;
+
+ return $this->$initializer($arg0, $arg1);
+
+ default:
+ return $this->$initializer($this, $argv);
+ }
+ }
+
+ /**
+ * Creates a new pipeline context and returns it, or returns the results of
+ * a pipeline executed inside the optionally provided callable object.
+ *
+ * @param mixed ... Array of options, a callable for execution, or both.
+ *
+ * @return Pipeline|array
+ */
+ public function pipeline(/* arguments */)
+ {
+ return $this->sharedContextFactory('createPipeline', func_get_args());
+ }
+
+ /**
+ * Actual pipeline context initializer method.
+ *
+ * @param array $options Options for the context.
+ * @param mixed $callable Optional callable used to execute the context.
+ *
+ * @return Pipeline|array
+ */
+ protected function createPipeline(array $options = null, $callable = null)
+ {
+ if (isset($options['atomic']) && $options['atomic']) {
+ $class = 'Predis\Pipeline\Atomic';
+ } elseif (isset($options['fire-and-forget']) && $options['fire-and-forget']) {
+ $class = 'Predis\Pipeline\FireAndForget';
+ } else {
+ $class = 'Predis\Pipeline\Pipeline';
+ }
+
+ /*
+ * @var ClientContextInterface
+ */
+ $pipeline = new $class($this);
+
+ if (isset($callable)) {
+ return $pipeline->execute($callable);
+ }
+
+ return $pipeline;
+ }
+
+ /**
+ * Creates a new transaction context and returns it, or returns the results
+ * of a transaction executed inside the optionally provided callable object.
+ *
+ * @param mixed ... Array of options, a callable for execution, or both.
+ *
+ * @return MultiExecTransaction|array
+ */
+ public function transaction(/* arguments */)
+ {
+ return $this->sharedContextFactory('createTransaction', func_get_args());
+ }
+
+ /**
+ * Actual transaction context initializer method.
+ *
+ * @param array $options Options for the context.
+ * @param mixed $callable Optional callable used to execute the context.
+ *
+ * @return MultiExecTransaction|array
+ */
+ protected function createTransaction(array $options = null, $callable = null)
+ {
+ $transaction = new MultiExecTransaction($this, $options);
+
+ if (isset($callable)) {
+ return $transaction->execute($callable);
+ }
+
+ return $transaction;
+ }
+
+ /**
+ * Creates a new publish/subscribe context and returns it, or starts its loop
+ * inside the optionally provided callable object.
+ *
+ * @param mixed ... Array of options, a callable for execution, or both.
+ *
+ * @return PubSubConsumer|null
+ */
+ public function pubSubLoop(/* arguments */)
+ {
+ return $this->sharedContextFactory('createPubSub', func_get_args());
+ }
+
+ /**
+ * Actual publish/subscribe context initializer method.
+ *
+ * @param array $options Options for the context.
+ * @param mixed $callable Optional callable used to execute the context.
+ *
+ * @return PubSubConsumer|null
+ */
+ protected function createPubSub(array $options = null, $callable = null)
+ {
+ $pubsub = new PubSubConsumer($this, $options);
+
+ if (!isset($callable)) {
+ return $pubsub;
+ }
+
+ foreach ($pubsub as $message) {
+ if (call_user_func($callable, $pubsub, $message) === false) {
+ $pubsub->stop();
+ }
+ }
+ }
+
+ /**
+ * Creates a new monitor consumer and returns it.
+ *
+ * @return MonitorConsumer
+ */
+ public function monitor()
+ {
+ return new MonitorConsumer($this);
+ }
+
+ /**
+ * @return \Traversable<string, static>
+ */
+ #[\ReturnTypeWillChange]
+ public function getIterator()
+ {
+ $clients = array();
+ $connection = $this->getConnection();
+
+ if (!$connection instanceof \Traversable) {
+ return new \ArrayIterator(array(
+ (string) $connection => new static($connection, $this->getOptions())
+ ));
+ }
+
+ foreach ($connection as $node) {
+ $clients[(string) $node] = new static($node, $this->getOptions());
+ }
+
+ return new \ArrayIterator($clients);
+ }
+}
diff --git a/vendor/predis/predis/src/ClientContextInterface.php b/vendor/predis/predis/src/ClientContextInterface.php
new file mode 100644
index 0000000..85e4edc
--- /dev/null
+++ b/vendor/predis/predis/src/ClientContextInterface.php
@@ -0,0 +1,199 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Interface defining a client-side context such as a pipeline or transaction.
+ *
+ * @method $this del(array|string $keys)
+ * @method $this dump($key)
+ * @method $this exists($key)
+ * @method $this expire($key, $seconds)
+ * @method $this expireat($key, $timestamp)
+ * @method $this keys($pattern)
+ * @method $this move($key, $db)
+ * @method $this object($subcommand, $key)
+ * @method $this persist($key)
+ * @method $this pexpire($key, $milliseconds)
+ * @method $this pexpireat($key, $timestamp)
+ * @method $this pttl($key)
+ * @method $this randomkey()
+ * @method $this rename($key, $target)
+ * @method $this renamenx($key, $target)
+ * @method $this scan($cursor, array $options = null)
+ * @method $this sort($key, array $options = null)
+ * @method $this ttl($key)
+ * @method $this type($key)
+ * @method $this append($key, $value)
+ * @method $this bitcount($key, $start = null, $end = null)
+ * @method $this bitop($operation, $destkey, $key)
+ * @method $this bitfield($key, $subcommand, ...$subcommandArg)
+ * @method $this bitpos($key, $bit, $start = null, $end = null)
+ * @method $this decr($key)
+ * @method $this decrby($key, $decrement)
+ * @method $this get($key)
+ * @method $this getbit($key, $offset)
+ * @method $this getrange($key, $start, $end)
+ * @method $this getset($key, $value)
+ * @method $this incr($key)
+ * @method $this incrby($key, $increment)
+ * @method $this incrbyfloat($key, $increment)
+ * @method $this mget(array $keys)
+ * @method $this mset(array $dictionary)
+ * @method $this msetnx(array $dictionary)
+ * @method $this psetex($key, $milliseconds, $value)
+ * @method $this set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
+ * @method $this setbit($key, $offset, $value)
+ * @method $this setex($key, $seconds, $value)
+ * @method $this setnx($key, $value)
+ * @method $this setrange($key, $offset, $value)
+ * @method $this strlen($key)
+ * @method $this hdel($key, array $fields)
+ * @method $this hexists($key, $field)
+ * @method $this hget($key, $field)
+ * @method $this hgetall($key)
+ * @method $this hincrby($key, $field, $increment)
+ * @method $this hincrbyfloat($key, $field, $increment)
+ * @method $this hkeys($key)
+ * @method $this hlen($key)
+ * @method $this hmget($key, array $fields)
+ * @method $this hmset($key, array $dictionary)
+ * @method $this hscan($key, $cursor, array $options = null)
+ * @method $this hset($key, $field, $value)
+ * @method $this hsetnx($key, $field, $value)
+ * @method $this hvals($key)
+ * @method $this hstrlen($key, $field)
+ * @method $this blpop(array|string $keys, $timeout)
+ * @method $this brpop(array|string $keys, $timeout)
+ * @method $this brpoplpush($source, $destination, $timeout)
+ * @method $this lindex($key, $index)
+ * @method $this linsert($key, $whence, $pivot, $value)
+ * @method $this llen($key)
+ * @method $this lpop($key)
+ * @method $this lpush($key, array $values)
+ * @method $this lpushx($key, array $values)
+ * @method $this lrange($key, $start, $stop)
+ * @method $this lrem($key, $count, $value)
+ * @method $this lset($key, $index, $value)
+ * @method $this ltrim($key, $start, $stop)
+ * @method $this rpop($key)
+ * @method $this rpoplpush($source, $destination)
+ * @method $this rpush($key, array $values)
+ * @method $this rpushx($key, array $values)
+ * @method $this sadd($key, array $members)
+ * @method $this scard($key)
+ * @method $this sdiff(array|string $keys)
+ * @method $this sdiffstore($destination, array|string $keys)
+ * @method $this sinter(array|string $keys)
+ * @method $this sinterstore($destination, array|string $keys)
+ * @method $this sismember($key, $member)
+ * @method $this smembers($key)
+ * @method $this smove($source, $destination, $member)
+ * @method $this spop($key, $count = null)
+ * @method $this srandmember($key, $count = null)
+ * @method $this srem($key, $member)
+ * @method $this sscan($key, $cursor, array $options = null)
+ * @method $this sunion(array|string $keys)
+ * @method $this sunionstore($destination, array|string $keys)
+ * @method $this zadd($key, array $membersAndScoresDictionary)
+ * @method $this zcard($key)
+ * @method $this zcount($key, $min, $max)
+ * @method $this zincrby($key, $increment, $member)
+ * @method $this zinterstore($destination, array|string $keys, array $options = null)
+ * @method $this zrange($key, $start, $stop, array $options = null)
+ * @method $this zrangebyscore($key, $min, $max, array $options = null)
+ * @method $this zrank($key, $member)
+ * @method $this zrem($key, $member)
+ * @method $this zremrangebyrank($key, $start, $stop)
+ * @method $this zremrangebyscore($key, $min, $max)
+ * @method $this zrevrange($key, $start, $stop, array $options = null)
+ * @method $this zrevrangebyscore($key, $max, $min, array $options = null)
+ * @method $this zrevrank($key, $member)
+ * @method $this zunionstore($destination, array|string $keys, array $options = null)
+ * @method $this zscore($key, $member)
+ * @method $this zscan($key, $cursor, array $options = null)
+ * @method $this zrangebylex($key, $start, $stop, array $options = null)
+ * @method $this zrevrangebylex($key, $start, $stop, array $options = null)
+ * @method $this zremrangebylex($key, $min, $max)
+ * @method $this zlexcount($key, $min, $max)
+ * @method $this pfadd($key, array $elements)
+ * @method $this pfmerge($destinationKey, array|string $sourceKeys)
+ * @method $this pfcount(array|string $keys)
+ * @method $this pubsub($subcommand, $argument)
+ * @method $this publish($channel, $message)
+ * @method $this discard()
+ * @method $this exec()
+ * @method $this multi()
+ * @method $this unwatch()
+ * @method $this watch($key)
+ * @method $this eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
+ * @method $this evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
+ * @method $this script($subcommand, $argument = null)
+ * @method $this auth($password)
+ * @method $this echo($message)
+ * @method $this ping($message = null)
+ * @method $this select($database)
+ * @method $this bgrewriteaof()
+ * @method $this bgsave()
+ * @method $this client($subcommand, $argument = null)
+ * @method $this config($subcommand, $argument = null)
+ * @method $this dbsize()
+ * @method $this flushall()
+ * @method $this flushdb()
+ * @method $this info($section = null)
+ * @method $this lastsave()
+ * @method $this save()
+ * @method $this slaveof($host, $port)
+ * @method $this slowlog($subcommand, $argument = null)
+ * @method $this time()
+ * @method $this command()
+ * @method $this geoadd($key, $longitude, $latitude, $member)
+ * @method $this geohash($key, array $members)
+ * @method $this geopos($key, array $members)
+ * @method $this geodist($key, $member1, $member2, $unit = null)
+ * @method $this georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
+ * @method $this georadiusbymember($key, $member, $radius, $unit, array $options = null)
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ClientContextInterface
+{
+ /**
+ * Sends the specified command instance to Redis.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return mixed
+ */
+ public function executeCommand(CommandInterface $command);
+
+ /**
+ * Sends the specified command with its arguments to Redis.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return mixed
+ */
+ public function __call($method, $arguments);
+
+ /**
+ * Starts the execution of the context.
+ *
+ * @param mixed $callable Optional callback for execution.
+ *
+ * @return array
+ */
+ public function execute($callable = null);
+}
diff --git a/vendor/predis/predis/src/ClientException.php b/vendor/predis/predis/src/ClientException.php
new file mode 100644
index 0000000..6c07aaf
--- /dev/null
+++ b/vendor/predis/predis/src/ClientException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+/**
+ * Exception class that identifies client-side errors.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ClientException extends PredisException
+{
+}
diff --git a/vendor/predis/predis/src/ClientInterface.php b/vendor/predis/predis/src/ClientInterface.php
new file mode 100644
index 0000000..f61dcf6
--- /dev/null
+++ b/vendor/predis/predis/src/ClientInterface.php
@@ -0,0 +1,240 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+use Predis\Command\CommandInterface;
+use Predis\Configuration\OptionsInterface;
+use Predis\Connection\ConnectionInterface;
+use Predis\Profile\ProfileInterface;
+
+/**
+ * Interface defining a client able to execute commands against Redis.
+ *
+ * All the commands exposed by the client generally have the same signature as
+ * described by the Redis documentation, but some of them offer an additional
+ * and more friendly interface to ease programming which is described in the
+ * following list of methods:
+ *
+ * @method int del(array|string $keys)
+ * @method string|null dump($key)
+ * @method int exists($key)
+ * @method int expire($key, $seconds)
+ * @method int expireat($key, $timestamp)
+ * @method array keys($pattern)
+ * @method int move($key, $db)
+ * @method mixed object($subcommand, $key)
+ * @method int persist($key)
+ * @method int pexpire($key, $milliseconds)
+ * @method int pexpireat($key, $timestamp)
+ * @method int pttl($key)
+ * @method string|null randomkey()
+ * @method mixed rename($key, $target)
+ * @method int renamenx($key, $target)
+ * @method array scan($cursor, array $options = null)
+ * @method array sort($key, array $options = null)
+ * @method int ttl($key)
+ * @method mixed type($key)
+ * @method int append($key, $value)
+ * @method int bitcount($key, $start = null, $end = null)
+ * @method int bitop($operation, $destkey, $key)
+ * @method array|null bitfield($key, $subcommand, ...$subcommandArg)
+ * @method int bitpos($key, $bit, $start = null, $end = null)
+ * @method int decr($key)
+ * @method int decrby($key, $decrement)
+ * @method string|null get($key)
+ * @method int getbit($key, $offset)
+ * @method string getrange($key, $start, $end)
+ * @method string|null getset($key, $value)
+ * @method int incr($key)
+ * @method int incrby($key, $increment)
+ * @method string incrbyfloat($key, $increment)
+ * @method array mget(array $keys)
+ * @method mixed mset(array $dictionary)
+ * @method int msetnx(array $dictionary)
+ * @method mixed psetex($key, $milliseconds, $value)
+ * @method mixed set($key, $value, $expireResolution = null, $expireTTL = null, $flag = null)
+ * @method int setbit($key, $offset, $value)
+ * @method int setex($key, $seconds, $value)
+ * @method int setnx($key, $value)
+ * @method int setrange($key, $offset, $value)
+ * @method int strlen($key)
+ * @method int hdel($key, array $fields)
+ * @method int hexists($key, $field)
+ * @method string|null hget($key, $field)
+ * @method array hgetall($key)
+ * @method int hincrby($key, $field, $increment)
+ * @method string hincrbyfloat($key, $field, $increment)
+ * @method array hkeys($key)
+ * @method int hlen($key)
+ * @method array hmget($key, array $fields)
+ * @method mixed hmset($key, array $dictionary)
+ * @method array hscan($key, $cursor, array $options = null)
+ * @method int hset($key, $field, $value)
+ * @method int hsetnx($key, $field, $value)
+ * @method array hvals($key)
+ * @method int hstrlen($key, $field)
+ * @method array|null blpop(array|string $keys, $timeout)
+ * @method array|null brpop(array|string $keys, $timeout)
+ * @method string|null brpoplpush($source, $destination, $timeout)
+ * @method string|null lindex($key, $index)
+ * @method int linsert($key, $whence, $pivot, $value)
+ * @method int llen($key)
+ * @method string|null lpop($key)
+ * @method int lpush($key, array $values)
+ * @method int lpushx($key, array $values)
+ * @method array lrange($key, $start, $stop)
+ * @method int lrem($key, $count, $value)
+ * @method mixed lset($key, $index, $value)
+ * @method mixed ltrim($key, $start, $stop)
+ * @method string|null rpop($key)
+ * @method string|null rpoplpush($source, $destination)
+ * @method int rpush($key, array $values)
+ * @method int rpushx($key, array $values)
+ * @method int sadd($key, array $members)
+ * @method int scard($key)
+ * @method array sdiff(array|string $keys)
+ * @method int sdiffstore($destination, array|string $keys)
+ * @method array sinter(array|string $keys)
+ * @method int sinterstore($destination, array|string $keys)
+ * @method int sismember($key, $member)
+ * @method array smembers($key)
+ * @method int smove($source, $destination, $member)
+ * @method string|null spop($key, $count = null)
+ * @method string|null srandmember($key, $count = null)
+ * @method int srem($key, $member)
+ * @method array sscan($key, $cursor, array $options = null)
+ * @method array sunion(array|string $keys)
+ * @method int sunionstore($destination, array|string $keys)
+ * @method int zadd($key, array $membersAndScoresDictionary)
+ * @method int zcard($key)
+ * @method string zcount($key, $min, $max)
+ * @method string zincrby($key, $increment, $member)
+ * @method int zinterstore($destination, array|string $keys, array $options = null)
+ * @method array zrange($key, $start, $stop, array $options = null)
+ * @method array zrangebyscore($key, $min, $max, array $options = null)
+ * @method int|null zrank($key, $member)
+ * @method int zrem($key, $member)
+ * @method int zremrangebyrank($key, $start, $stop)
+ * @method int zremrangebyscore($key, $min, $max)
+ * @method array zrevrange($key, $start, $stop, array $options = null)
+ * @method array zrevrangebyscore($key, $max, $min, array $options = null)
+ * @method int|null zrevrank($key, $member)
+ * @method int zunionstore($destination, array|string $keys, array $options = null)
+ * @method string|null zscore($key, $member)
+ * @method array zscan($key, $cursor, array $options = null)
+ * @method array zrangebylex($key, $start, $stop, array $options = null)
+ * @method array zrevrangebylex($key, $start, $stop, array $options = null)
+ * @method int zremrangebylex($key, $min, $max)
+ * @method int zlexcount($key, $min, $max)
+ * @method int pfadd($key, array $elements)
+ * @method mixed pfmerge($destinationKey, array|string $sourceKeys)
+ * @method int pfcount(array|string $keys)
+ * @method mixed pubsub($subcommand, $argument)
+ * @method int publish($channel, $message)
+ * @method mixed discard()
+ * @method array|null exec()
+ * @method mixed multi()
+ * @method mixed unwatch()
+ * @method mixed watch($key)
+ * @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
+ * @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
+ * @method mixed script($subcommand, $argument = null)
+ * @method mixed auth($password)
+ * @method string echo($message)
+ * @method mixed ping($message = null)
+ * @method mixed select($database)
+ * @method mixed bgrewriteaof()
+ * @method mixed bgsave()
+ * @method mixed client($subcommand, $argument = null)
+ * @method mixed config($subcommand, $argument = null)
+ * @method int dbsize()
+ * @method mixed flushall()
+ * @method mixed flushdb()
+ * @method array info($section = null)
+ * @method int lastsave()
+ * @method mixed save()
+ * @method mixed slaveof($host, $port)
+ * @method mixed slowlog($subcommand, $argument = null)
+ * @method array time()
+ * @method array command()
+ * @method int geoadd($key, $longitude, $latitude, $member)
+ * @method array geohash($key, array $members)
+ * @method array geopos($key, array $members)
+ * @method string|null geodist($key, $member1, $member2, $unit = null)
+ * @method array georadius($key, $longitude, $latitude, $radius, $unit, array $options = null)
+ * @method array georadiusbymember($key, $member, $radius, $unit, array $options = null)
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ClientInterface
+{
+ /**
+ * Returns the server profile used by the client.
+ *
+ * @return ProfileInterface
+ */
+ public function getProfile();
+
+ /**
+ * Returns the client options specified upon initialization.
+ *
+ * @return OptionsInterface
+ */
+ public function getOptions();
+
+ /**
+ * Opens the underlying connection to the server.
+ */
+ public function connect();
+
+ /**
+ * Closes the underlying connection from the server.
+ */
+ public function disconnect();
+
+ /**
+ * Returns the underlying connection instance.
+ *
+ * @return ConnectionInterface
+ */
+ public function getConnection();
+
+ /**
+ * Creates a new instance of the specified Redis command.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return CommandInterface
+ */
+ public function createCommand($method, $arguments = array());
+
+ /**
+ * Executes the specified Redis command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return mixed
+ */
+ public function executeCommand(CommandInterface $command);
+
+ /**
+ * Creates a Redis command with the specified arguments and sends a request
+ * to the server.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return mixed
+ */
+ public function __call($method, $arguments);
+}
diff --git a/vendor/predis/predis/src/Cluster/ClusterStrategy.php b/vendor/predis/predis/src/Cluster/ClusterStrategy.php
new file mode 100644
index 0000000..1891907
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/ClusterStrategy.php
@@ -0,0 +1,469 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster;
+
+use Predis\Command\CommandInterface;
+use Predis\Command\ScriptCommand;
+
+/**
+ * Common class implementing the logic needed to support clustering strategies.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class ClusterStrategy implements StrategyInterface
+{
+ protected $commands;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->commands = $this->getDefaultCommands();
+ }
+
+ /**
+ * Returns the default map of supported commands with their handlers.
+ *
+ * @return array
+ */
+ protected function getDefaultCommands()
+ {
+ $getKeyFromFirstArgument = array($this, 'getKeyFromFirstArgument');
+ $getKeyFromAllArguments = array($this, 'getKeyFromAllArguments');
+
+ return array(
+ /* commands operating on the key space */
+ 'EXISTS' => $getKeyFromAllArguments,
+ 'DEL' => $getKeyFromAllArguments,
+ 'TYPE' => $getKeyFromFirstArgument,
+ 'EXPIRE' => $getKeyFromFirstArgument,
+ 'EXPIREAT' => $getKeyFromFirstArgument,
+ 'PERSIST' => $getKeyFromFirstArgument,
+ 'PEXPIRE' => $getKeyFromFirstArgument,
+ 'PEXPIREAT' => $getKeyFromFirstArgument,
+ 'TTL' => $getKeyFromFirstArgument,
+ 'PTTL' => $getKeyFromFirstArgument,
+ 'SORT' => array($this, 'getKeyFromSortCommand'),
+ 'DUMP' => $getKeyFromFirstArgument,
+ 'RESTORE' => $getKeyFromFirstArgument,
+
+ /* commands operating on string values */
+ 'APPEND' => $getKeyFromFirstArgument,
+ 'DECR' => $getKeyFromFirstArgument,
+ 'DECRBY' => $getKeyFromFirstArgument,
+ 'GET' => $getKeyFromFirstArgument,
+ 'GETBIT' => $getKeyFromFirstArgument,
+ 'MGET' => $getKeyFromAllArguments,
+ 'SET' => $getKeyFromFirstArgument,
+ 'GETRANGE' => $getKeyFromFirstArgument,
+ 'GETSET' => $getKeyFromFirstArgument,
+ 'INCR' => $getKeyFromFirstArgument,
+ 'INCRBY' => $getKeyFromFirstArgument,
+ 'INCRBYFLOAT' => $getKeyFromFirstArgument,
+ 'SETBIT' => $getKeyFromFirstArgument,
+ 'SETEX' => $getKeyFromFirstArgument,
+ 'MSET' => array($this, 'getKeyFromInterleavedArguments'),
+ 'MSETNX' => array($this, 'getKeyFromInterleavedArguments'),
+ 'SETNX' => $getKeyFromFirstArgument,
+ 'SETRANGE' => $getKeyFromFirstArgument,
+ 'STRLEN' => $getKeyFromFirstArgument,
+ 'SUBSTR' => $getKeyFromFirstArgument,
+ 'BITOP' => array($this, 'getKeyFromBitOp'),
+ 'BITCOUNT' => $getKeyFromFirstArgument,
+ 'BITFIELD' => $getKeyFromFirstArgument,
+
+ /* commands operating on lists */
+ 'LINSERT' => $getKeyFromFirstArgument,
+ 'LINDEX' => $getKeyFromFirstArgument,
+ 'LLEN' => $getKeyFromFirstArgument,
+ 'LPOP' => $getKeyFromFirstArgument,
+ 'RPOP' => $getKeyFromFirstArgument,
+ 'RPOPLPUSH' => $getKeyFromAllArguments,
+ 'BLPOP' => array($this, 'getKeyFromBlockingListCommands'),
+ 'BRPOP' => array($this, 'getKeyFromBlockingListCommands'),
+ 'BRPOPLPUSH' => array($this, 'getKeyFromBlockingListCommands'),
+ 'LPUSH' => $getKeyFromFirstArgument,
+ 'LPUSHX' => $getKeyFromFirstArgument,
+ 'RPUSH' => $getKeyFromFirstArgument,
+ 'RPUSHX' => $getKeyFromFirstArgument,
+ 'LRANGE' => $getKeyFromFirstArgument,
+ 'LREM' => $getKeyFromFirstArgument,
+ 'LSET' => $getKeyFromFirstArgument,
+ 'LTRIM' => $getKeyFromFirstArgument,
+
+ /* commands operating on sets */
+ 'SADD' => $getKeyFromFirstArgument,
+ 'SCARD' => $getKeyFromFirstArgument,
+ 'SDIFF' => $getKeyFromAllArguments,
+ 'SDIFFSTORE' => $getKeyFromAllArguments,
+ 'SINTER' => $getKeyFromAllArguments,
+ 'SINTERSTORE' => $getKeyFromAllArguments,
+ 'SUNION' => $getKeyFromAllArguments,
+ 'SUNIONSTORE' => $getKeyFromAllArguments,
+ 'SISMEMBER' => $getKeyFromFirstArgument,
+ 'SMEMBERS' => $getKeyFromFirstArgument,
+ 'SSCAN' => $getKeyFromFirstArgument,
+ 'SPOP' => $getKeyFromFirstArgument,
+ 'SRANDMEMBER' => $getKeyFromFirstArgument,
+ 'SREM' => $getKeyFromFirstArgument,
+
+ /* commands operating on sorted sets */
+ 'ZADD' => $getKeyFromFirstArgument,
+ 'ZCARD' => $getKeyFromFirstArgument,
+ 'ZCOUNT' => $getKeyFromFirstArgument,
+ 'ZINCRBY' => $getKeyFromFirstArgument,
+ 'ZINTERSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
+ 'ZRANGE' => $getKeyFromFirstArgument,
+ 'ZRANGEBYSCORE' => $getKeyFromFirstArgument,
+ 'ZRANK' => $getKeyFromFirstArgument,
+ 'ZREM' => $getKeyFromFirstArgument,
+ 'ZREMRANGEBYRANK' => $getKeyFromFirstArgument,
+ 'ZREMRANGEBYSCORE' => $getKeyFromFirstArgument,
+ 'ZREVRANGE' => $getKeyFromFirstArgument,
+ 'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
+ 'ZREVRANK' => $getKeyFromFirstArgument,
+ 'ZSCORE' => $getKeyFromFirstArgument,
+ 'ZUNIONSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
+ 'ZSCAN' => $getKeyFromFirstArgument,
+ 'ZLEXCOUNT' => $getKeyFromFirstArgument,
+ 'ZRANGEBYLEX' => $getKeyFromFirstArgument,
+ 'ZREMRANGEBYLEX' => $getKeyFromFirstArgument,
+ 'ZREVRANGEBYLEX' => $getKeyFromFirstArgument,
+
+ /* commands operating on hashes */
+ 'HDEL' => $getKeyFromFirstArgument,
+ 'HEXISTS' => $getKeyFromFirstArgument,
+ 'HGET' => $getKeyFromFirstArgument,
+ 'HGETALL' => $getKeyFromFirstArgument,
+ 'HMGET' => $getKeyFromFirstArgument,
+ 'HMSET' => $getKeyFromFirstArgument,
+ 'HINCRBY' => $getKeyFromFirstArgument,
+ 'HINCRBYFLOAT' => $getKeyFromFirstArgument,
+ 'HKEYS' => $getKeyFromFirstArgument,
+ 'HLEN' => $getKeyFromFirstArgument,
+ 'HSET' => $getKeyFromFirstArgument,
+ 'HSETNX' => $getKeyFromFirstArgument,
+ 'HVALS' => $getKeyFromFirstArgument,
+ 'HSCAN' => $getKeyFromFirstArgument,
+ 'HSTRLEN' => $getKeyFromFirstArgument,
+
+ /* commands operating on HyperLogLog */
+ 'PFADD' => $getKeyFromFirstArgument,
+ 'PFCOUNT' => $getKeyFromAllArguments,
+ 'PFMERGE' => $getKeyFromAllArguments,
+
+ /* scripting */
+ 'EVAL' => array($this, 'getKeyFromScriptingCommands'),
+ 'EVALSHA' => array($this, 'getKeyFromScriptingCommands'),
+
+ /* commands performing geospatial operations */
+ 'GEOADD' => $getKeyFromFirstArgument,
+ 'GEOHASH' => $getKeyFromFirstArgument,
+ 'GEOPOS' => $getKeyFromFirstArgument,
+ 'GEODIST' => $getKeyFromFirstArgument,
+ 'GEORADIUS' => array($this, 'getKeyFromGeoradiusCommands'),
+ 'GEORADIUSBYMEMBER' => array($this, 'getKeyFromGeoradiusCommands'),
+ );
+ }
+
+ /**
+ * Returns the list of IDs for the supported commands.
+ *
+ * @return array
+ */
+ public function getSupportedCommands()
+ {
+ return array_keys($this->commands);
+ }
+
+ /**
+ * Sets an handler for the specified command ID.
+ *
+ * The signature of the callback must have a single parameter of type
+ * Predis\Command\CommandInterface.
+ *
+ * When the callback argument is omitted or NULL, the previously associated
+ * handler for the specified command ID is removed.
+ *
+ * @param string $commandID Command ID.
+ * @param mixed $callback A valid callable object, or NULL to unset the handler.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setCommandHandler($commandID, $callback = null)
+ {
+ $commandID = strtoupper($commandID);
+
+ if (!isset($callback)) {
+ unset($this->commands[$commandID]);
+
+ return;
+ }
+
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException(
+ 'The argument must be a callable object or NULL.'
+ );
+ }
+
+ $this->commands[$commandID] = $callback;
+ }
+
+ /**
+ * Extracts the key from the first argument of a command instance.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string
+ */
+ protected function getKeyFromFirstArgument(CommandInterface $command)
+ {
+ return $command->getArgument(0);
+ }
+
+ /**
+ * Extracts the key from a command with multiple keys only when all keys in
+ * the arguments array produce the same hash.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromAllArguments(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+
+ if ($this->checkSameSlotForKeys($arguments)) {
+ return $arguments[0];
+ }
+ }
+
+ /**
+ * Extracts the key from a command with multiple keys only when all keys in
+ * the arguments array produce the same hash.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromInterleavedArguments(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $keys = array();
+
+ for ($i = 0; $i < count($arguments); $i += 2) {
+ $keys[] = $arguments[$i];
+ }
+
+ if ($this->checkSameSlotForKeys($keys)) {
+ return $arguments[0];
+ }
+ }
+
+ /**
+ * Extracts the key from SORT command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromSortCommand(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $firstKey = $arguments[0];
+
+ if (1 === $argc = count($arguments)) {
+ return $firstKey;
+ }
+
+ $keys = array($firstKey);
+
+ for ($i = 1; $i < $argc; ++$i) {
+ if (strtoupper($arguments[$i]) === 'STORE') {
+ $keys[] = $arguments[++$i];
+ }
+ }
+
+ if ($this->checkSameSlotForKeys($keys)) {
+ return $firstKey;
+ }
+ }
+
+ /**
+ * Extracts the key from BLPOP and BRPOP commands.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromBlockingListCommands(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+
+ if ($this->checkSameSlotForKeys(array_slice($arguments, 0, count($arguments) - 1))) {
+ return $arguments[0];
+ }
+ }
+
+ /**
+ * Extracts the key from BITOP command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromBitOp(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+
+ if ($this->checkSameSlotForKeys(array_slice($arguments, 1, count($arguments)))) {
+ return $arguments[1];
+ }
+ }
+
+ /**
+ * Extracts the key from GEORADIUS and GEORADIUSBYMEMBER commands.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromGeoradiusCommands(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $argc = count($arguments);
+ $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;
+
+ if ($argc > $startIndex) {
+ $keys = array($arguments[0]);
+
+ for ($i = $startIndex; $i < $argc; ++$i) {
+ $argument = strtoupper($arguments[$i]);
+ if ($argument === 'STORE' || $argument === 'STOREDIST') {
+ $keys[] = $arguments[++$i];
+ }
+ }
+
+ if ($this->checkSameSlotForKeys($keys)) {
+ return $arguments[0];
+ } else {
+ return;
+ }
+ }
+
+ return $arguments[0];
+ }
+
+ /**
+ * Extracts the key from ZINTERSTORE and ZUNIONSTORE commands.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromZsetAggregationCommands(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $keys = array_merge(array($arguments[0]), array_slice($arguments, 2, $arguments[1]));
+
+ if ($this->checkSameSlotForKeys($keys)) {
+ return $arguments[0];
+ }
+ }
+
+ /**
+ * Extracts the key from EVAL and EVALSHA commands.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return string|null
+ */
+ protected function getKeyFromScriptingCommands(CommandInterface $command)
+ {
+ if ($command instanceof ScriptCommand) {
+ $keys = $command->getKeys();
+ } else {
+ $keys = array_slice($args = $command->getArguments(), 2, $args[1]);
+ }
+
+ if ($keys && $this->checkSameSlotForKeys($keys)) {
+ return $keys[0];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlot(CommandInterface $command)
+ {
+ $slot = $command->getSlot();
+
+ if (!isset($slot) && isset($this->commands[$cmdID = $command->getId()])) {
+ $key = call_user_func($this->commands[$cmdID], $command);
+
+ if (isset($key)) {
+ $slot = $this->getSlotByKey($key);
+ $command->setSlot($slot);
+ }
+ }
+
+ return $slot;
+ }
+
+ /**
+ * Checks if the specified array of keys will generate the same hash.
+ *
+ * @param array $keys Array of keys.
+ *
+ * @return bool
+ */
+ protected function checkSameSlotForKeys(array $keys)
+ {
+ if (!$count = count($keys)) {
+ return false;
+ }
+
+ $currentSlot = $this->getSlotByKey($keys[0]);
+
+ for ($i = 1; $i < $count; ++$i) {
+ $nextSlot = $this->getSlotByKey($keys[$i]);
+
+ if ($currentSlot !== $nextSlot) {
+ return false;
+ }
+
+ $currentSlot = $nextSlot;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns only the hashable part of a key (delimited by "{...}"), or the
+ * whole key if a key tag is not found in the string.
+ *
+ * @param string $key A key.
+ *
+ * @return string
+ */
+ protected function extractKeyTag($key)
+ {
+ if (false !== $start = strpos($key, '{')) {
+ if (false !== ($end = strpos($key, '}', $start)) && $end !== ++$start) {
+ $key = substr($key, $start, $end - $start);
+ }
+ }
+
+ return $key;
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/Distributor/DistributorInterface.php b/vendor/predis/predis/src/Cluster/Distributor/DistributorInterface.php
new file mode 100644
index 0000000..831f52c
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Distributor/DistributorInterface.php
@@ -0,0 +1,82 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Distributor;
+
+use Predis\Cluster\Hash\HashGeneratorInterface;
+
+/**
+ * A distributor implements the logic to automatically distribute keys among
+ * several nodes for client-side sharding.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface DistributorInterface
+{
+ /**
+ * Adds a node to the distributor with an optional weight.
+ *
+ * @param mixed $node Node object.
+ * @param int $weight Weight for the node.
+ */
+ public function add($node, $weight = null);
+
+ /**
+ * Removes a node from the distributor.
+ *
+ * @param mixed $node Node object.
+ */
+ public function remove($node);
+
+ /**
+ * Returns the corresponding slot of a node from the distributor using the
+ * computed hash of a key.
+ *
+ * @param mixed $hash
+ *
+ * @return mixed
+ */
+ public function getSlot($hash);
+
+ /**
+ * Returns a node from the distributor using its assigned slot ID.
+ *
+ * @param mixed $slot
+ *
+ * @return mixed|null
+ */
+ public function getBySlot($slot);
+
+ /**
+ * Returns a node from the distributor using the computed hash of a key.
+ *
+ * @param mixed $hash
+ *
+ * @return mixed
+ */
+ public function getByHash($hash);
+
+ /**
+ * Returns a node from the distributor mapping to the specified value.
+ *
+ * @param string $value
+ *
+ * @return mixed
+ */
+ public function get($value);
+
+ /**
+ * Returns the underlying hash generator instance.
+ *
+ * @return HashGeneratorInterface
+ */
+ public function getHashGenerator();
+}
diff --git a/vendor/predis/predis/src/Cluster/Distributor/EmptyRingException.php b/vendor/predis/predis/src/Cluster/Distributor/EmptyRingException.php
new file mode 100644
index 0000000..039f2f2
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Distributor/EmptyRingException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Distributor;
+
+/**
+ * Exception class that identifies empty rings.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class EmptyRingException extends \Exception
+{
+}
diff --git a/vendor/predis/predis/src/Cluster/Distributor/HashRing.php b/vendor/predis/predis/src/Cluster/Distributor/HashRing.php
new file mode 100644
index 0000000..a0c7ae8
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Distributor/HashRing.php
@@ -0,0 +1,270 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Distributor;
+
+use Predis\Cluster\Hash\HashGeneratorInterface;
+
+/**
+ * This class implements an hashring-based distributor that uses the same
+ * algorithm of memcache to distribute keys in a cluster using client-side
+ * sharding.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ * @author Lorenzo Castelli <lcastelli@gmail.com>
+ */
+class HashRing implements DistributorInterface, HashGeneratorInterface
+{
+ const DEFAULT_REPLICAS = 128;
+ const DEFAULT_WEIGHT = 100;
+
+ private $ring;
+ private $ringKeys;
+ private $ringKeysCount;
+ private $replicas;
+ private $nodeHashCallback;
+ private $nodes = array();
+
+ /**
+ * @param int $replicas Number of replicas in the ring.
+ * @param mixed $nodeHashCallback Callback returning a string used to calculate the hash of nodes.
+ */
+ public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null)
+ {
+ $this->replicas = $replicas;
+ $this->nodeHashCallback = $nodeHashCallback;
+ }
+
+ /**
+ * Adds a node to the ring with an optional weight.
+ *
+ * @param mixed $node Node object.
+ * @param int $weight Weight for the node.
+ */
+ public function add($node, $weight = null)
+ {
+ // In case of collisions in the hashes of the nodes, the node added
+ // last wins, thus the order in which nodes are added is significant.
+ $this->nodes[] = array(
+ 'object' => $node,
+ 'weight' => (int) $weight ?: $this::DEFAULT_WEIGHT,
+ );
+
+ $this->reset();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($node)
+ {
+ // A node is removed by resetting the ring so that it's recreated from
+ // scratch, in order to reassign possible hashes with collisions to the
+ // right node according to the order in which they were added in the
+ // first place.
+ for ($i = 0; $i < count($this->nodes); ++$i) {
+ if ($this->nodes[$i]['object'] === $node) {
+ array_splice($this->nodes, $i, 1);
+ $this->reset();
+
+ break;
+ }
+ }
+ }
+
+ /**
+ * Resets the distributor.
+ */
+ private function reset()
+ {
+ unset(
+ $this->ring,
+ $this->ringKeys,
+ $this->ringKeysCount
+ );
+ }
+
+ /**
+ * Returns the initialization status of the distributor.
+ *
+ * @return bool
+ */
+ private function isInitialized()
+ {
+ return isset($this->ringKeys);
+ }
+
+ /**
+ * Calculates the total weight of all the nodes in the distributor.
+ *
+ * @return int
+ */
+ private function computeTotalWeight()
+ {
+ $totalWeight = 0;
+
+ foreach ($this->nodes as $node) {
+ $totalWeight += $node['weight'];
+ }
+
+ return $totalWeight;
+ }
+
+ /**
+ * Initializes the distributor.
+ */
+ private function initialize()
+ {
+ if ($this->isInitialized()) {
+ return;
+ }
+
+ if (!$this->nodes) {
+ throw new EmptyRingException('Cannot initialize an empty hashring.');
+ }
+
+ $this->ring = array();
+ $totalWeight = $this->computeTotalWeight();
+ $nodesCount = count($this->nodes);
+
+ foreach ($this->nodes as $node) {
+ $weightRatio = $node['weight'] / $totalWeight;
+ $this->addNodeToRing($this->ring, $node, $nodesCount, $this->replicas, $weightRatio);
+ }
+
+ ksort($this->ring, SORT_NUMERIC);
+ $this->ringKeys = array_keys($this->ring);
+ $this->ringKeysCount = count($this->ringKeys);
+ }
+
+ /**
+ * Implements the logic needed to add a node to the hashring.
+ *
+ * @param array $ring Source hashring.
+ * @param mixed $node Node object to be added.
+ * @param int $totalNodes Total number of nodes.
+ * @param int $replicas Number of replicas in the ring.
+ * @param float $weightRatio Weight ratio for the node.
+ */
+ protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
+ {
+ $nodeObject = $node['object'];
+ $nodeHash = $this->getNodeHash($nodeObject);
+ $replicas = (int) round($weightRatio * $totalNodes * $replicas);
+
+ for ($i = 0; $i < $replicas; ++$i) {
+ $key = $this->hash("$nodeHash:$i");
+ $ring[$key] = $nodeObject;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getNodeHash($nodeObject)
+ {
+ if (!isset($this->nodeHashCallback)) {
+ return (string) $nodeObject;
+ }
+
+ return call_user_func($this->nodeHashCallback, $nodeObject);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hash($value)
+ {
+ return crc32($value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getByHash($hash)
+ {
+ return $this->ring[$this->getSlot($hash)];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getBySlot($slot)
+ {
+ $this->initialize();
+
+ if (isset($this->ring[$slot])) {
+ return $this->ring[$slot];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlot($hash)
+ {
+ $this->initialize();
+
+ $ringKeys = $this->ringKeys;
+ $upper = $this->ringKeysCount - 1;
+ $lower = 0;
+
+ while ($lower <= $upper) {
+ $index = ($lower + $upper) >> 1;
+ $item = $ringKeys[$index];
+
+ if ($item > $hash) {
+ $upper = $index - 1;
+ } elseif ($item < $hash) {
+ $lower = $index + 1;
+ } else {
+ return $item;
+ }
+ }
+
+ return $ringKeys[$this->wrapAroundStrategy($upper, $lower, $this->ringKeysCount)];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($value)
+ {
+ $hash = $this->hash($value);
+ $node = $this->getByHash($hash);
+
+ return $node;
+ }
+
+ /**
+ * Implements a strategy to deal with wrap-around errors during binary searches.
+ *
+ * @param int $upper
+ * @param int $lower
+ * @param int $ringKeysCount
+ *
+ * @return int
+ */
+ protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
+ {
+ // Binary search for the last item in ringkeys with a value less or
+ // equal to the key. If no such item exists, return the last item.
+ return $upper >= 0 ? $upper : $ringKeysCount - 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHashGenerator()
+ {
+ return $this;
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/Distributor/KetamaRing.php b/vendor/predis/predis/src/Cluster/Distributor/KetamaRing.php
new file mode 100644
index 0000000..dc77f32
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Distributor/KetamaRing.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Distributor;
+
+/**
+ * This class implements an hashring-based distributor that uses the same
+ * algorithm of libketama to distribute keys in a cluster using client-side
+ * sharding.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ * @author Lorenzo Castelli <lcastelli@gmail.com>
+ */
+class KetamaRing extends HashRing
+{
+ const DEFAULT_REPLICAS = 160;
+
+ /**
+ * @param mixed $nodeHashCallback Callback returning a string used to calculate the hash of nodes.
+ */
+ public function __construct($nodeHashCallback = null)
+ {
+ parent::__construct($this::DEFAULT_REPLICAS, $nodeHashCallback);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
+ {
+ $nodeObject = $node['object'];
+ $nodeHash = $this->getNodeHash($nodeObject);
+ $replicas = (int) floor($weightRatio * $totalNodes * ($replicas / 4));
+
+ for ($i = 0; $i < $replicas; ++$i) {
+ $unpackedDigest = unpack('V4', md5("$nodeHash-$i", true));
+
+ foreach ($unpackedDigest as $key) {
+ $ring[$key] = $nodeObject;
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hash($value)
+ {
+ $hash = unpack('V', md5($value, true));
+
+ return $hash[1];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
+ {
+ // Binary search for the first item in ringkeys with a value greater
+ // or equal to the key. If no such item exists, return the first item.
+ return $lower < $ringKeysCount ? $lower : 0;
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/Hash/CRC16.php b/vendor/predis/predis/src/Cluster/Hash/CRC16.php
new file mode 100644
index 0000000..c52ed2a
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Hash/CRC16.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Hash;
+
+/**
+ * Hash generator implementing the CRC-CCITT-16 algorithm used by redis-cluster.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class CRC16 implements HashGeneratorInterface
+{
+ private static $CCITT_16 = array(
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hash($value)
+ {
+ // CRC-CCITT-16 algorithm
+ $crc = 0;
+ $CCITT_16 = self::$CCITT_16;
+
+ $value = (string) $value;
+ $strlen = strlen($value);
+
+ for ($i = 0; $i < $strlen; ++$i) {
+ $crc = (($crc << 8) ^ $CCITT_16[($crc >> 8) ^ ord($value[$i])]) & 0xFFFF;
+ }
+
+ return $crc;
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php b/vendor/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php
new file mode 100644
index 0000000..271b9e7
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/Hash/HashGeneratorInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster\Hash;
+
+/**
+ * An hash generator implements the logic used to calculate the hash of a key to
+ * distribute operations among Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface HashGeneratorInterface
+{
+ /**
+ * Generates an hash from a string to be used for distribution.
+ *
+ * @param string $value String value.
+ *
+ * @return int
+ */
+ public function hash($value);
+}
diff --git a/vendor/predis/predis/src/Cluster/PredisStrategy.php b/vendor/predis/predis/src/Cluster/PredisStrategy.php
new file mode 100644
index 0000000..2066842
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/PredisStrategy.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster;
+
+use Predis\Cluster\Distributor\DistributorInterface;
+use Predis\Cluster\Distributor\HashRing;
+
+/**
+ * Default cluster strategy used by Predis to handle client-side sharding.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PredisStrategy extends ClusterStrategy
+{
+ protected $distributor;
+
+ /**
+ * @param DistributorInterface $distributor Optional distributor instance.
+ */
+ public function __construct(DistributorInterface $distributor = null)
+ {
+ parent::__construct();
+
+ $this->distributor = $distributor ?: new HashRing();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlotByKey($key)
+ {
+ $key = $this->extractKeyTag($key);
+ $hash = $this->distributor->hash($key);
+ $slot = $this->distributor->getSlot($hash);
+
+ return $slot;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function checkSameSlotForKeys(array $keys)
+ {
+ if (!$count = count($keys)) {
+ return false;
+ }
+
+ $currentKey = $this->extractKeyTag($keys[0]);
+
+ for ($i = 1; $i < $count; ++$i) {
+ $nextKey = $this->extractKeyTag($keys[$i]);
+
+ if ($currentKey !== $nextKey) {
+ return false;
+ }
+
+ $currentKey = $nextKey;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDistributor()
+ {
+ return $this->distributor;
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/RedisStrategy.php b/vendor/predis/predis/src/Cluster/RedisStrategy.php
new file mode 100644
index 0000000..df0bdb4
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/RedisStrategy.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster;
+
+use Predis\Cluster\Hash\CRC16;
+use Predis\Cluster\Hash\HashGeneratorInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Default class used by Predis to calculate hashes out of keys of
+ * commands supported by redis-cluster.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisStrategy extends ClusterStrategy
+{
+ protected $hashGenerator;
+
+ /**
+ * @param HashGeneratorInterface $hashGenerator Hash generator instance.
+ */
+ public function __construct(HashGeneratorInterface $hashGenerator = null)
+ {
+ parent::__construct();
+
+ $this->hashGenerator = $hashGenerator ?: new CRC16();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlotByKey($key)
+ {
+ $key = $this->extractKeyTag($key);
+ $slot = $this->hashGenerator->hash($key) & 0x3FFF;
+
+ return $slot;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDistributor()
+ {
+ throw new NotSupportedException(
+ 'This cluster strategy does not provide an external distributor'
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Cluster/StrategyInterface.php b/vendor/predis/predis/src/Cluster/StrategyInterface.php
new file mode 100644
index 0000000..cdf7d09
--- /dev/null
+++ b/vendor/predis/predis/src/Cluster/StrategyInterface.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Cluster;
+
+use Predis\Cluster\Distributor\DistributorInterface;
+use Predis\Command\CommandInterface;
+
+/**
+ * Interface for classes defining the strategy used to calculate an hash out of
+ * keys extracted from supported commands.
+ *
+ * This is mostly useful to support clustering via client-side sharding.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface StrategyInterface
+{
+ /**
+ * Returns a slot for the given command used for clustering distribution or
+ * NULL when this is not possible.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return int
+ */
+ public function getSlot(CommandInterface $command);
+
+ /**
+ * Returns a slot for the given key used for clustering distribution or NULL
+ * when this is not possible.
+ *
+ * @param string $key Key string.
+ *
+ * @return int
+ */
+ public function getSlotByKey($key);
+
+ /**
+ * Returns a distributor instance to be used by the cluster.
+ *
+ * @return DistributorInterface
+ */
+ public function getDistributor();
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/CursorBasedIterator.php b/vendor/predis/predis/src/Collection/Iterator/CursorBasedIterator.php
new file mode 100644
index 0000000..a52e04f
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/CursorBasedIterator.php
@@ -0,0 +1,196 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Provides the base implementation for a fully-rewindable PHP iterator that can
+ * incrementally iterate over cursor-based collections stored on Redis using the
+ * commands in the `SCAN` family.
+ *
+ * Given their incremental nature with multiple fetches, these kind of iterators
+ * offer limited guarantees about the returned elements because the collection
+ * can change several times during the iteration process.
+ *
+ * @see http://redis.io/commands/scan
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class CursorBasedIterator implements \Iterator
+{
+ protected $client;
+ protected $match;
+ protected $count;
+
+ protected $valid;
+ protected $fetchmore;
+ protected $elements;
+ protected $cursor;
+ protected $position;
+ protected $current;
+
+ /**
+ * @param ClientInterface $client Client connected to Redis.
+ * @param string $match Pattern to match during the server-side iteration.
+ * @param int $count Hint used by Redis to compute the number of results per iteration.
+ */
+ public function __construct(ClientInterface $client, $match = null, $count = null)
+ {
+ $this->client = $client;
+ $this->match = $match;
+ $this->count = $count;
+
+ $this->reset();
+ }
+
+ /**
+ * Ensures that the client supports the specified Redis command required to
+ * fetch elements from the server to perform the iteration.
+ *
+ * @param ClientInterface $client Client connected to Redis.
+ * @param string $commandID Command ID.
+ *
+ * @throws NotSupportedException
+ */
+ protected function requiredCommand(ClientInterface $client, $commandID)
+ {
+ if (!$client->getProfile()->supportsCommand($commandID)) {
+ throw new NotSupportedException("The current profile does not support '$commandID'.");
+ }
+ }
+
+ /**
+ * Resets the inner state of the iterator.
+ */
+ protected function reset()
+ {
+ $this->valid = true;
+ $this->fetchmore = true;
+ $this->elements = array();
+ $this->cursor = 0;
+ $this->position = -1;
+ $this->current = null;
+ }
+
+ /**
+ * Returns an array of options for the `SCAN` command.
+ *
+ * @return array
+ */
+ protected function getScanOptions()
+ {
+ $options = array();
+
+ if (strlen(strval($this->match)) > 0) {
+ $options['MATCH'] = $this->match;
+ }
+
+ if ($this->count > 0) {
+ $options['COUNT'] = $this->count;
+ }
+
+ return $options;
+ }
+
+ /**
+ * Fetches a new set of elements from the remote collection, effectively
+ * advancing the iteration process.
+ *
+ * @return array
+ */
+ abstract protected function executeCommand();
+
+ /**
+ * Populates the local buffer of elements fetched from the server during
+ * the iteration.
+ */
+ protected function fetch()
+ {
+ list($cursor, $elements) = $this->executeCommand();
+
+ if (!$cursor) {
+ $this->fetchmore = false;
+ }
+
+ $this->cursor = $cursor;
+ $this->elements = $elements;
+ }
+
+ /**
+ * Extracts next values for key() and current().
+ */
+ protected function extractNext()
+ {
+ ++$this->position;
+ $this->current = array_shift($this->elements);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ $this->reset();
+ $this->next();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ tryFetch: {
+ if (!$this->elements && $this->fetchmore) {
+ $this->fetch();
+ }
+
+ if ($this->elements) {
+ $this->extractNext();
+ } elseif ($this->cursor) {
+ goto tryFetch;
+ } else {
+ $this->valid = false;
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ return $this->valid;
+ }
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/HashKey.php b/vendor/predis/predis/src/Collection/Iterator/HashKey.php
new file mode 100644
index 0000000..5bd07c2
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/HashKey.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+
+/**
+ * Abstracts the iteration of fields and values of an hash by leveraging the
+ * HSCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @link http://redis.io/commands/scan
+ */
+class HashKey extends CursorBasedIterator
+{
+ protected $key;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ClientInterface $client, $key, $match = null, $count = null)
+ {
+ $this->requiredCommand($client, 'HSCAN');
+
+ parent::__construct($client, $match, $count);
+
+ $this->key = $key;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeCommand()
+ {
+ return $this->client->hscan($this->key, $this->cursor, $this->getScanOptions());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractNext()
+ {
+ $this->position = key($this->elements);
+ $this->current = current($this->elements);
+
+ unset($this->elements[$this->position]);
+ }
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/Keyspace.php b/vendor/predis/predis/src/Collection/Iterator/Keyspace.php
new file mode 100644
index 0000000..5d985b9
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/Keyspace.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+
+/**
+ * Abstracts the iteration of the keyspace on a Redis instance by leveraging the
+ * SCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @link http://redis.io/commands/scan
+ */
+class Keyspace extends CursorBasedIterator
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ClientInterface $client, $match = null, $count = null)
+ {
+ $this->requiredCommand($client, 'SCAN');
+
+ parent::__construct($client, $match, $count);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeCommand()
+ {
+ return $this->client->scan($this->cursor, $this->getScanOptions());
+ }
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/ListKey.php b/vendor/predis/predis/src/Collection/Iterator/ListKey.php
new file mode 100644
index 0000000..01f06e9
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/ListKey.php
@@ -0,0 +1,181 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Abstracts the iteration of items stored in a list by leveraging the LRANGE
+ * command wrapped in a fully-rewindable PHP iterator.
+ *
+ * This iterator tries to emulate the behaviour of cursor-based iterators based
+ * on the SCAN-family of commands introduced in Redis <= 2.8, meaning that due
+ * to its incremental nature with multiple fetches it can only offer limited
+ * guarantees on the returned elements because the collection can change several
+ * times (trimmed, deleted, overwritten) during the iteration process.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @link http://redis.io/commands/lrange
+ */
+class ListKey implements \Iterator
+{
+ protected $client;
+ protected $count;
+ protected $key;
+
+ protected $valid;
+ protected $fetchmore;
+ protected $elements;
+ protected $position;
+ protected $current;
+
+ /**
+ * @param ClientInterface $client Client connected to Redis.
+ * @param string $key Redis list key.
+ * @param int $count Number of items retrieved on each fetch operation.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(ClientInterface $client, $key, $count = 10)
+ {
+ $this->requiredCommand($client, 'LRANGE');
+
+ if ((false === $count = filter_var($count, FILTER_VALIDATE_INT)) || $count < 0) {
+ throw new \InvalidArgumentException('The $count argument must be a positive integer.');
+ }
+
+ $this->client = $client;
+ $this->key = $key;
+ $this->count = $count;
+
+ $this->reset();
+ }
+
+ /**
+ * Ensures that the client instance supports the specified Redis command
+ * required to fetch elements from the server to perform the iteration.
+ *
+ * @param ClientInterface $client Client connected to Redis.
+ * @param string $commandID Command ID.
+ *
+ * @throws NotSupportedException
+ */
+ protected function requiredCommand(ClientInterface $client, $commandID)
+ {
+ if (!$client->getProfile()->supportsCommand($commandID)) {
+ throw new NotSupportedException("The current profile does not support '$commandID'.");
+ }
+ }
+
+ /**
+ * Resets the inner state of the iterator.
+ */
+ protected function reset()
+ {
+ $this->valid = true;
+ $this->fetchmore = true;
+ $this->elements = array();
+ $this->position = -1;
+ $this->current = null;
+ }
+
+ /**
+ * Fetches a new set of elements from the remote collection, effectively
+ * advancing the iteration process.
+ *
+ * @return array
+ */
+ protected function executeCommand()
+ {
+ return $this->client->lrange($this->key, $this->position + 1, $this->position + $this->count);
+ }
+
+ /**
+ * Populates the local buffer of elements fetched from the server during the
+ * iteration.
+ */
+ protected function fetch()
+ {
+ $elements = $this->executeCommand();
+
+ if (count($elements) < $this->count) {
+ $this->fetchmore = false;
+ }
+
+ $this->elements = $elements;
+ }
+
+ /**
+ * Extracts next values for key() and current().
+ */
+ protected function extractNext()
+ {
+ ++$this->position;
+ $this->current = array_shift($this->elements);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ $this->reset();
+ $this->next();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ if (!$this->elements && $this->fetchmore) {
+ $this->fetch();
+ }
+
+ if ($this->elements) {
+ $this->extractNext();
+ } else {
+ $this->valid = false;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ return $this->valid;
+ }
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/SetKey.php b/vendor/predis/predis/src/Collection/Iterator/SetKey.php
new file mode 100644
index 0000000..bf25439
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/SetKey.php
@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+
+/**
+ * Abstracts the iteration of members stored in a set by leveraging the SSCAN
+ * command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @link http://redis.io/commands/scan
+ */
+class SetKey extends CursorBasedIterator
+{
+ protected $key;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ClientInterface $client, $key, $match = null, $count = null)
+ {
+ $this->requiredCommand($client, 'SSCAN');
+
+ parent::__construct($client, $match, $count);
+
+ $this->key = $key;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeCommand()
+ {
+ return $this->client->sscan($this->key, $this->cursor, $this->getScanOptions());
+ }
+}
diff --git a/vendor/predis/predis/src/Collection/Iterator/SortedSetKey.php b/vendor/predis/predis/src/Collection/Iterator/SortedSetKey.php
new file mode 100644
index 0000000..d96122a
--- /dev/null
+++ b/vendor/predis/predis/src/Collection/Iterator/SortedSetKey.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Collection\Iterator;
+
+use Predis\ClientInterface;
+
+/**
+ * Abstracts the iteration of members stored in a sorted set by leveraging the
+ * ZSCAN command (Redis >= 2.8) wrapped in a fully-rewindable PHP iterator.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @link http://redis.io/commands/scan
+ */
+class SortedSetKey extends CursorBasedIterator
+{
+ protected $key;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ClientInterface $client, $key, $match = null, $count = null)
+ {
+ $this->requiredCommand($client, 'ZSCAN');
+
+ parent::__construct($client, $match, $count);
+
+ $this->key = $key;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeCommand()
+ {
+ return $this->client->zscan($this->key, $this->cursor, $this->getScanOptions());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractNext()
+ {
+ $this->position = key($this->elements);
+ $this->current = current($this->elements);
+
+ unset($this->elements[$this->position]);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/Command.php b/vendor/predis/predis/src/Command/Command.php
new file mode 100644
index 0000000..59e1813
--- /dev/null
+++ b/vendor/predis/predis/src/Command/Command.php
@@ -0,0 +1,129 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * Base class for Redis commands.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class Command implements CommandInterface
+{
+ private $slot;
+ private $arguments = array();
+
+ /**
+ * Returns a filtered array of the arguments.
+ *
+ * @param array $arguments List of arguments.
+ *
+ * @return array
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return $arguments;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setArguments(array $arguments)
+ {
+ $this->arguments = $this->filterArguments($arguments);
+ unset($this->slot);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRawArguments(array $arguments)
+ {
+ $this->arguments = $arguments;
+ unset($this->slot);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getArguments()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getArgument($index)
+ {
+ if (isset($this->arguments[$index])) {
+ return $this->arguments[$index];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSlot($slot)
+ {
+ $this->slot = $slot;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlot()
+ {
+ if (isset($this->slot)) {
+ return $this->slot;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ return $data;
+ }
+
+ /**
+ * Normalizes the arguments array passed to a Redis command.
+ *
+ * @param array $arguments Arguments for a command.
+ *
+ * @return array
+ */
+ public static function normalizeArguments(array $arguments)
+ {
+ if (count($arguments) === 1 && isset($arguments[0]) && is_array($arguments[0])) {
+ return $arguments[0];
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Normalizes the arguments array passed to a variadic Redis command.
+ *
+ * @param array $arguments Arguments for a command.
+ *
+ * @return array
+ */
+ public static function normalizeVariadic(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ return array_merge(array($arguments[0]), $arguments[1]);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/CommandInterface.php b/vendor/predis/predis/src/Command/CommandInterface.php
new file mode 100644
index 0000000..9f349e1
--- /dev/null
+++ b/vendor/predis/predis/src/Command/CommandInterface.php
@@ -0,0 +1,81 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * Defines an abstraction representing a Redis command.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface CommandInterface
+{
+ /**
+ * Returns the ID of the Redis command. By convention, command identifiers
+ * must always be uppercase.
+ *
+ * @return string
+ */
+ public function getId();
+
+ /**
+ * Assign the specified slot to the command for clustering distribution.
+ *
+ * @param int $slot Slot ID.
+ */
+ public function setSlot($slot);
+
+ /**
+ * Returns the assigned slot of the command for clustering distribution.
+ *
+ * @return int|null
+ */
+ public function getSlot();
+
+ /**
+ * Sets the arguments for the command.
+ *
+ * @param array $arguments List of arguments.
+ */
+ public function setArguments(array $arguments);
+
+ /**
+ * Sets the raw arguments for the command without processing them.
+ *
+ * @param array $arguments List of arguments.
+ */
+ public function setRawArguments(array $arguments);
+
+ /**
+ * Gets the arguments of the command.
+ *
+ * @return array
+ */
+ public function getArguments();
+
+ /**
+ * Gets the argument of the command at the specified index.
+ *
+ * @param int $index Index of the desired argument.
+ *
+ * @return mixed|null
+ */
+ public function getArgument($index);
+
+ /**
+ * Parses a raw response and returns a PHP object.
+ *
+ * @param string $data Binary string containing the whole response.
+ *
+ * @return mixed
+ */
+ public function parseResponse($data);
+}
diff --git a/vendor/predis/predis/src/Command/ConnectionAuth.php b/vendor/predis/predis/src/Command/ConnectionAuth.php
new file mode 100644
index 0000000..c8c9ded
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ConnectionAuth.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/auth
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionAuth extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'AUTH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ConnectionEcho.php b/vendor/predis/predis/src/Command/ConnectionEcho.php
new file mode 100644
index 0000000..fd49609
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ConnectionEcho.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/echo
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionEcho extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ECHO';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ConnectionPing.php b/vendor/predis/predis/src/Command/ConnectionPing.php
new file mode 100644
index 0000000..fa9d734
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ConnectionPing.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/ping
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionPing extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PING';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ConnectionQuit.php b/vendor/predis/predis/src/Command/ConnectionQuit.php
new file mode 100644
index 0000000..e59e31e
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ConnectionQuit.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/quit
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionQuit extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'QUIT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ConnectionSelect.php b/vendor/predis/predis/src/Command/ConnectionSelect.php
new file mode 100644
index 0000000..1da8256
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ConnectionSelect.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/select
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionSelect extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SELECT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoAdd.php b/vendor/predis/predis/src/Command/GeospatialGeoAdd.php
new file mode 100644
index 0000000..adca2ca
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoAdd.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/geoadd
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoAdd extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEOADD';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ foreach (array_pop($arguments) as $item) {
+ $arguments = array_merge($arguments, $item);
+ }
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoDist.php b/vendor/predis/predis/src/Command/GeospatialGeoDist.php
new file mode 100644
index 0000000..17c5f54
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoDist.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/geodist
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoDist extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEODIST';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoHash.php b/vendor/predis/predis/src/Command/GeospatialGeoHash.php
new file mode 100644
index 0000000..2eccaf4
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoHash.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/geohash
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoHash extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEOHASH';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ $members = array_pop($arguments);
+ $arguments = array_merge($arguments, $members);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoPos.php b/vendor/predis/predis/src/Command/GeospatialGeoPos.php
new file mode 100644
index 0000000..6b7a9a3
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoPos.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/geopos
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoPos extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEOPOS';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ $members = array_pop($arguments);
+ $arguments = array_merge($arguments, $members);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoRadius.php b/vendor/predis/predis/src/Command/GeospatialGeoRadius.php
new file mode 100644
index 0000000..f205214
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoRadius.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/georadius
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoRadius extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEORADIUS';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if ($arguments && is_array(end($arguments))) {
+ $options = array_change_key_case(array_pop($arguments), CASE_UPPER);
+
+ if (isset($options['WITHCOORD']) && $options['WITHCOORD'] == true) {
+ $arguments[] = 'WITHCOORD';
+ }
+
+ if (isset($options['WITHDIST']) && $options['WITHDIST'] == true) {
+ $arguments[] = 'WITHDIST';
+ }
+
+ if (isset($options['WITHHASH']) && $options['WITHHASH'] == true) {
+ $arguments[] = 'WITHHASH';
+ }
+
+ if (isset($options['COUNT'])) {
+ $arguments[] = 'COUNT';
+ $arguments[] = $options['COUNT'];
+ }
+
+ if (isset($options['SORT'])) {
+ $arguments[] = strtoupper($options['SORT']);
+ }
+
+ if (isset($options['STORE'])) {
+ $arguments[] = 'STORE';
+ $arguments[] = $options['STORE'];
+ }
+
+ if (isset($options['STOREDIST'])) {
+ $arguments[] = 'STOREDIST';
+ $arguments[] = $options['STOREDIST'];
+ }
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/GeospatialGeoRadiusByMember.php b/vendor/predis/predis/src/Command/GeospatialGeoRadiusByMember.php
new file mode 100644
index 0000000..abfff7b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/GeospatialGeoRadiusByMember.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/georadiusbymember
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class GeospatialGeoRadiusByMember extends GeospatialGeoRadius
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GEORADIUSBYMEMBER';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashDelete.php b/vendor/predis/predis/src/Command/HashDelete.php
new file mode 100644
index 0000000..d5d4c38
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashDelete.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hdel
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashDelete extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HDEL';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashExists.php b/vendor/predis/predis/src/Command/HashExists.php
new file mode 100644
index 0000000..ed8dc89
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashExists.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hexists
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashExists extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HEXISTS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashGet.php b/vendor/predis/predis/src/Command/HashGet.php
new file mode 100644
index 0000000..20f33da
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashGet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hget
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashGet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HGET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashGetAll.php b/vendor/predis/predis/src/Command/HashGetAll.php
new file mode 100644
index 0000000..d698675
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashGetAll.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hgetall
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashGetAll extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HGETALL';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ $result = array();
+
+ for ($i = 0; $i < count($data); ++$i) {
+ $result[$data[$i]] = $data[++$i];
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashGetMultiple.php b/vendor/predis/predis/src/Command/HashGetMultiple.php
new file mode 100644
index 0000000..820ce95
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashGetMultiple.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hmget
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashGetMultiple extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HMGET';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashIncrementBy.php b/vendor/predis/predis/src/Command/HashIncrementBy.php
new file mode 100644
index 0000000..a37359f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashIncrementBy.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hincrby
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashIncrementBy extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HINCRBY';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashIncrementByFloat.php b/vendor/predis/predis/src/Command/HashIncrementByFloat.php
new file mode 100644
index 0000000..bce9714
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashIncrementByFloat.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hincrbyfloat
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashIncrementByFloat extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HINCRBYFLOAT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashKeys.php b/vendor/predis/predis/src/Command/HashKeys.php
new file mode 100644
index 0000000..2826602
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashKeys.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hkeys
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashKeys extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HKEYS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashLength.php b/vendor/predis/predis/src/Command/HashLength.php
new file mode 100644
index 0000000..d70926f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashLength.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hlen
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashLength extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HLEN';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashScan.php b/vendor/predis/predis/src/Command/HashScan.php
new file mode 100644
index 0000000..afde74e
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashScan.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hscan
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashScan extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HSCAN';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 3 && is_array($arguments[2])) {
+ $options = $this->prepareOptions(array_pop($arguments));
+ $arguments = array_merge($arguments, $options);
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ protected function prepareOptions($options)
+ {
+ $options = array_change_key_case($options, CASE_UPPER);
+ $normalized = array();
+
+ if (!empty($options['MATCH'])) {
+ $normalized[] = 'MATCH';
+ $normalized[] = $options['MATCH'];
+ }
+
+ if (!empty($options['COUNT'])) {
+ $normalized[] = 'COUNT';
+ $normalized[] = $options['COUNT'];
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if (is_array($data)) {
+ $fields = $data[1];
+ $result = array();
+
+ for ($i = 0; $i < count($fields); ++$i) {
+ $result[$fields[$i]] = $fields[++$i];
+ }
+
+ $data[1] = $result;
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashSet.php b/vendor/predis/predis/src/Command/HashSet.php
new file mode 100644
index 0000000..cfff3c2
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashSet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hset
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashSet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HSET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashSetMultiple.php b/vendor/predis/predis/src/Command/HashSetMultiple.php
new file mode 100644
index 0000000..6069e2a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashSetMultiple.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hmset
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashSetMultiple extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HMSET';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ $flattenedKVs = array($arguments[0]);
+ $args = $arguments[1];
+
+ foreach ($args as $k => $v) {
+ $flattenedKVs[] = $k;
+ $flattenedKVs[] = $v;
+ }
+
+ return $flattenedKVs;
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashSetPreserve.php b/vendor/predis/predis/src/Command/HashSetPreserve.php
new file mode 100644
index 0000000..7a29116
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashSetPreserve.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hsetnx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashSetPreserve extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HSETNX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashStringLength.php b/vendor/predis/predis/src/Command/HashStringLength.php
new file mode 100644
index 0000000..7cfda80
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashStringLength.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hstrlen
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashStringLength extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HSTRLEN';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HashValues.php b/vendor/predis/predis/src/Command/HashValues.php
new file mode 100644
index 0000000..0a5ea5f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HashValues.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/hvals
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HashValues extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'HVALS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HyperLogLogAdd.php b/vendor/predis/predis/src/Command/HyperLogLogAdd.php
new file mode 100644
index 0000000..8fe49fc
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HyperLogLogAdd.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pfadd
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HyperLogLogAdd extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PFADD';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HyperLogLogCount.php b/vendor/predis/predis/src/Command/HyperLogLogCount.php
new file mode 100644
index 0000000..0afe542
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HyperLogLogCount.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pfcount
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HyperLogLogCount extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PFCOUNT';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/HyperLogLogMerge.php b/vendor/predis/predis/src/Command/HyperLogLogMerge.php
new file mode 100644
index 0000000..c160be5
--- /dev/null
+++ b/vendor/predis/predis/src/Command/HyperLogLogMerge.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pfmerge
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class HyperLogLogMerge extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PFMERGE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyDelete.php b/vendor/predis/predis/src/Command/KeyDelete.php
new file mode 100644
index 0000000..89bdfdb
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyDelete.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/del
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyDelete extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DEL';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyDump.php b/vendor/predis/predis/src/Command/KeyDump.php
new file mode 100644
index 0000000..6d9c488
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyDump.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/dump
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyDump extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DUMP';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyExists.php b/vendor/predis/predis/src/Command/KeyExists.php
new file mode 100644
index 0000000..29e0648
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyExists.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/exists
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyExists extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EXISTS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyExpire.php b/vendor/predis/predis/src/Command/KeyExpire.php
new file mode 100644
index 0000000..66f4406
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyExpire.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/expire
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyExpire extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EXPIRE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyExpireAt.php b/vendor/predis/predis/src/Command/KeyExpireAt.php
new file mode 100644
index 0000000..0ae1b2d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyExpireAt.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/expireat
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyExpireAt extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EXPIREAT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyKeys.php b/vendor/predis/predis/src/Command/KeyKeys.php
new file mode 100644
index 0000000..6d74c40
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyKeys.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/keys
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyKeys extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'KEYS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyMigrate.php b/vendor/predis/predis/src/Command/KeyMigrate.php
new file mode 100644
index 0000000..3324ef9
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyMigrate.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/migrate
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyMigrate extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MIGRATE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (is_array(end($arguments))) {
+ foreach (array_pop($arguments) as $modifier => $value) {
+ $modifier = strtoupper($modifier);
+
+ if ($modifier === 'COPY' && $value == true) {
+ $arguments[] = $modifier;
+ }
+
+ if ($modifier === 'REPLACE' && $value == true) {
+ $arguments[] = $modifier;
+ }
+ }
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyMove.php b/vendor/predis/predis/src/Command/KeyMove.php
new file mode 100644
index 0000000..c849f08
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyMove.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/move
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyMove extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MOVE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyPersist.php b/vendor/predis/predis/src/Command/KeyPersist.php
new file mode 100644
index 0000000..f0cb679
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyPersist.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/persist
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyPersist extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PERSIST';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyPreciseExpire.php b/vendor/predis/predis/src/Command/KeyPreciseExpire.php
new file mode 100644
index 0000000..258ec47
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyPreciseExpire.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pexpire
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyPreciseExpire extends KeyExpire
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PEXPIRE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyPreciseExpireAt.php b/vendor/predis/predis/src/Command/KeyPreciseExpireAt.php
new file mode 100644
index 0000000..e419218
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyPreciseExpireAt.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pexpireat
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyPreciseExpireAt extends KeyExpireAt
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PEXPIREAT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyPreciseTimeToLive.php b/vendor/predis/predis/src/Command/KeyPreciseTimeToLive.php
new file mode 100644
index 0000000..bdcd34b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyPreciseTimeToLive.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pttl
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyPreciseTimeToLive extends KeyTimeToLive
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PTTL';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyRandom.php b/vendor/predis/predis/src/Command/KeyRandom.php
new file mode 100644
index 0000000..b208b2d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyRandom.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/randomkey
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyRandom extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RANDOMKEY';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ return $data !== '' ? $data : null;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyRename.php b/vendor/predis/predis/src/Command/KeyRename.php
new file mode 100644
index 0000000..82e44fb
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyRename.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/rename
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyRename extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RENAME';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyRenamePreserve.php b/vendor/predis/predis/src/Command/KeyRenamePreserve.php
new file mode 100644
index 0000000..9793359
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyRenamePreserve.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/renamenx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyRenamePreserve extends KeyRename
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RENAMENX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyRestore.php b/vendor/predis/predis/src/Command/KeyRestore.php
new file mode 100644
index 0000000..a5b0b2d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyRestore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/restore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyRestore extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RESTORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyScan.php b/vendor/predis/predis/src/Command/KeyScan.php
new file mode 100644
index 0000000..05f5bb3
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyScan.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/scan
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyScan extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SCAN';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ $options = $this->prepareOptions(array_pop($arguments));
+ $arguments = array_merge($arguments, $options);
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ protected function prepareOptions($options)
+ {
+ $options = array_change_key_case($options, CASE_UPPER);
+ $normalized = array();
+
+ if (!empty($options['MATCH'])) {
+ $normalized[] = 'MATCH';
+ $normalized[] = $options['MATCH'];
+ }
+
+ if (!empty($options['COUNT'])) {
+ $normalized[] = 'COUNT';
+ $normalized[] = $options['COUNT'];
+ }
+
+ return $normalized;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeySort.php b/vendor/predis/predis/src/Command/KeySort.php
new file mode 100644
index 0000000..fd449f1
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeySort.php
@@ -0,0 +1,83 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sort
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeySort extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SORT';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 1) {
+ return $arguments;
+ }
+
+ $query = array($arguments[0]);
+ $sortParams = array_change_key_case($arguments[1], CASE_UPPER);
+
+ if (isset($sortParams['BY'])) {
+ $query[] = 'BY';
+ $query[] = $sortParams['BY'];
+ }
+
+ if (isset($sortParams['GET'])) {
+ $getargs = $sortParams['GET'];
+
+ if (is_array($getargs)) {
+ foreach ($getargs as $getarg) {
+ $query[] = 'GET';
+ $query[] = $getarg;
+ }
+ } else {
+ $query[] = 'GET';
+ $query[] = $getargs;
+ }
+ }
+
+ if (isset($sortParams['LIMIT']) &&
+ is_array($sortParams['LIMIT']) &&
+ count($sortParams['LIMIT']) == 2) {
+ $query[] = 'LIMIT';
+ $query[] = $sortParams['LIMIT'][0];
+ $query[] = $sortParams['LIMIT'][1];
+ }
+
+ if (isset($sortParams['SORT'])) {
+ $query[] = strtoupper($sortParams['SORT']);
+ }
+
+ if (isset($sortParams['ALPHA']) && $sortParams['ALPHA'] == true) {
+ $query[] = 'ALPHA';
+ }
+
+ if (isset($sortParams['STORE'])) {
+ $query[] = 'STORE';
+ $query[] = $sortParams['STORE'];
+ }
+
+ return $query;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyTimeToLive.php b/vendor/predis/predis/src/Command/KeyTimeToLive.php
new file mode 100644
index 0000000..67697a6
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyTimeToLive.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/ttl
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyTimeToLive extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'TTL';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/KeyType.php b/vendor/predis/predis/src/Command/KeyType.php
new file mode 100644
index 0000000..f4f06e4
--- /dev/null
+++ b/vendor/predis/predis/src/Command/KeyType.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/type
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyType extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'TYPE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListIndex.php b/vendor/predis/predis/src/Command/ListIndex.php
new file mode 100644
index 0000000..27c64be
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListIndex.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lindex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListIndex extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LINDEX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListInsert.php b/vendor/predis/predis/src/Command/ListInsert.php
new file mode 100644
index 0000000..7d53d11
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListInsert.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/linsert
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListInsert extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LINSERT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListLength.php b/vendor/predis/predis/src/Command/ListLength.php
new file mode 100644
index 0000000..6495beb
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListLength.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/llen
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListLength extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LLEN';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopFirst.php b/vendor/predis/predis/src/Command/ListPopFirst.php
new file mode 100644
index 0000000..84d5d67
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopFirst.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lpop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopFirst extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LPOP';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopFirstBlocking.php b/vendor/predis/predis/src/Command/ListPopFirstBlocking.php
new file mode 100644
index 0000000..7dc7c00
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopFirstBlocking.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/blpop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopFirstBlocking extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BLPOP';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[0])) {
+ list($arguments, $timeout) = $arguments;
+ array_push($arguments, $timeout);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopLast.php b/vendor/predis/predis/src/Command/ListPopLast.php
new file mode 100644
index 0000000..9e92db5
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopLast.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/rpop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopLast extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RPOP';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopLastBlocking.php b/vendor/predis/predis/src/Command/ListPopLastBlocking.php
new file mode 100644
index 0000000..781eb91
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopLastBlocking.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/brpop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopLastBlocking extends ListPopFirstBlocking
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BRPOP';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopLastPushHead.php b/vendor/predis/predis/src/Command/ListPopLastPushHead.php
new file mode 100644
index 0000000..f430eb2
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopLastPushHead.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/rpoplpush
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopLastPushHead extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RPOPLPUSH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPopLastPushHeadBlocking.php b/vendor/predis/predis/src/Command/ListPopLastPushHeadBlocking.php
new file mode 100644
index 0000000..ee9c93c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPopLastPushHeadBlocking.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/brpoplpush
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPopLastPushHeadBlocking extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BRPOPLPUSH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPushHead.php b/vendor/predis/predis/src/Command/ListPushHead.php
new file mode 100644
index 0000000..74bf7c4
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPushHead.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lpush
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPushHead extends ListPushTail
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LPUSH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPushHeadX.php b/vendor/predis/predis/src/Command/ListPushHeadX.php
new file mode 100644
index 0000000..8e136b8
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPushHeadX.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lpushx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPushHeadX extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LPUSHX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPushTail.php b/vendor/predis/predis/src/Command/ListPushTail.php
new file mode 100644
index 0000000..f2a057c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPushTail.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/rpush
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPushTail extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RPUSH';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListPushTailX.php b/vendor/predis/predis/src/Command/ListPushTailX.php
new file mode 100644
index 0000000..1af3645
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListPushTailX.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/rpushx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListPushTailX extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'RPUSHX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListRange.php b/vendor/predis/predis/src/Command/ListRange.php
new file mode 100644
index 0000000..32a21a6
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListRange.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lrange
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListRange extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LRANGE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListRemove.php b/vendor/predis/predis/src/Command/ListRemove.php
new file mode 100644
index 0000000..c580089
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListRemove.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lrem
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListRemove extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LREM';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListSet.php b/vendor/predis/predis/src/Command/ListSet.php
new file mode 100644
index 0000000..5e59864
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListSet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lset
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListSet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LSET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ListTrim.php b/vendor/predis/predis/src/Command/ListTrim.php
new file mode 100644
index 0000000..1931418
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ListTrim.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/ltrim
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ListTrim extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LTRIM';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PrefixableCommandInterface.php b/vendor/predis/predis/src/Command/PrefixableCommandInterface.php
new file mode 100644
index 0000000..6d54554
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PrefixableCommandInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * Defines a command whose keys can be prefixed.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface PrefixableCommandInterface extends CommandInterface
+{
+ /**
+ * Prefixes all the keys found in the arguments of the command.
+ *
+ * @param string $prefix String used to prefix the keys.
+ */
+ public function prefixKeys($prefix);
+}
diff --git a/vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php b/vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php
new file mode 100644
index 0000000..7520127
--- /dev/null
+++ b/vendor/predis/predis/src/Command/Processor/KeyPrefixProcessor.php
@@ -0,0 +1,450 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command\Processor;
+
+use Predis\Command\CommandInterface;
+use Predis\Command\PrefixableCommandInterface;
+
+/**
+ * Command processor capable of prefixing keys stored in the arguments of Redis
+ * commands supported.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class KeyPrefixProcessor implements ProcessorInterface
+{
+ private $prefix;
+ private $commands;
+
+ /**
+ * @param string $prefix Prefix for the keys.
+ */
+ public function __construct($prefix)
+ {
+ $this->prefix = $prefix;
+ $this->commands = array(
+ /* ---------------- Redis 1.2 ---------------- */
+ 'EXISTS' => 'static::all',
+ 'DEL' => 'static::all',
+ 'TYPE' => 'static::first',
+ 'KEYS' => 'static::first',
+ 'RENAME' => 'static::all',
+ 'RENAMENX' => 'static::all',
+ 'EXPIRE' => 'static::first',
+ 'EXPIREAT' => 'static::first',
+ 'TTL' => 'static::first',
+ 'MOVE' => 'static::first',
+ 'SORT' => 'static::sort',
+ 'DUMP' => 'static::first',
+ 'RESTORE' => 'static::first',
+ 'SET' => 'static::first',
+ 'SETNX' => 'static::first',
+ 'MSET' => 'static::interleaved',
+ 'MSETNX' => 'static::interleaved',
+ 'GET' => 'static::first',
+ 'MGET' => 'static::all',
+ 'GETSET' => 'static::first',
+ 'INCR' => 'static::first',
+ 'INCRBY' => 'static::first',
+ 'DECR' => 'static::first',
+ 'DECRBY' => 'static::first',
+ 'RPUSH' => 'static::first',
+ 'LPUSH' => 'static::first',
+ 'LLEN' => 'static::first',
+ 'LRANGE' => 'static::first',
+ 'LTRIM' => 'static::first',
+ 'LINDEX' => 'static::first',
+ 'LSET' => 'static::first',
+ 'LREM' => 'static::first',
+ 'LPOP' => 'static::first',
+ 'RPOP' => 'static::first',
+ 'RPOPLPUSH' => 'static::all',
+ 'SADD' => 'static::first',
+ 'SREM' => 'static::first',
+ 'SPOP' => 'static::first',
+ 'SMOVE' => 'static::skipLast',
+ 'SCARD' => 'static::first',
+ 'SISMEMBER' => 'static::first',
+ 'SINTER' => 'static::all',
+ 'SINTERSTORE' => 'static::all',
+ 'SUNION' => 'static::all',
+ 'SUNIONSTORE' => 'static::all',
+ 'SDIFF' => 'static::all',
+ 'SDIFFSTORE' => 'static::all',
+ 'SMEMBERS' => 'static::first',
+ 'SRANDMEMBER' => 'static::first',
+ 'ZADD' => 'static::first',
+ 'ZINCRBY' => 'static::first',
+ 'ZREM' => 'static::first',
+ 'ZRANGE' => 'static::first',
+ 'ZREVRANGE' => 'static::first',
+ 'ZRANGEBYSCORE' => 'static::first',
+ 'ZCARD' => 'static::first',
+ 'ZSCORE' => 'static::first',
+ 'ZREMRANGEBYSCORE' => 'static::first',
+ /* ---------------- Redis 2.0 ---------------- */
+ 'SETEX' => 'static::first',
+ 'APPEND' => 'static::first',
+ 'SUBSTR' => 'static::first',
+ 'BLPOP' => 'static::skipLast',
+ 'BRPOP' => 'static::skipLast',
+ 'ZUNIONSTORE' => 'static::zsetStore',
+ 'ZINTERSTORE' => 'static::zsetStore',
+ 'ZCOUNT' => 'static::first',
+ 'ZRANK' => 'static::first',
+ 'ZREVRANK' => 'static::first',
+ 'ZREMRANGEBYRANK' => 'static::first',
+ 'HSET' => 'static::first',
+ 'HSETNX' => 'static::first',
+ 'HMSET' => 'static::first',
+ 'HINCRBY' => 'static::first',
+ 'HGET' => 'static::first',
+ 'HMGET' => 'static::first',
+ 'HDEL' => 'static::first',
+ 'HEXISTS' => 'static::first',
+ 'HLEN' => 'static::first',
+ 'HKEYS' => 'static::first',
+ 'HVALS' => 'static::first',
+ 'HGETALL' => 'static::first',
+ 'SUBSCRIBE' => 'static::all',
+ 'UNSUBSCRIBE' => 'static::all',
+ 'PSUBSCRIBE' => 'static::all',
+ 'PUNSUBSCRIBE' => 'static::all',
+ 'PUBLISH' => 'static::first',
+ /* ---------------- Redis 2.2 ---------------- */
+ 'PERSIST' => 'static::first',
+ 'STRLEN' => 'static::first',
+ 'SETRANGE' => 'static::first',
+ 'GETRANGE' => 'static::first',
+ 'SETBIT' => 'static::first',
+ 'GETBIT' => 'static::first',
+ 'RPUSHX' => 'static::first',
+ 'LPUSHX' => 'static::first',
+ 'LINSERT' => 'static::first',
+ 'BRPOPLPUSH' => 'static::skipLast',
+ 'ZREVRANGEBYSCORE' => 'static::first',
+ 'WATCH' => 'static::all',
+ /* ---------------- Redis 2.6 ---------------- */
+ 'PTTL' => 'static::first',
+ 'PEXPIRE' => 'static::first',
+ 'PEXPIREAT' => 'static::first',
+ 'PSETEX' => 'static::first',
+ 'INCRBYFLOAT' => 'static::first',
+ 'BITOP' => 'static::skipFirst',
+ 'BITCOUNT' => 'static::first',
+ 'HINCRBYFLOAT' => 'static::first',
+ 'EVAL' => 'static::evalKeys',
+ 'EVALSHA' => 'static::evalKeys',
+ 'MIGRATE' => 'static::migrate',
+ /* ---------------- Redis 2.8 ---------------- */
+ 'SSCAN' => 'static::first',
+ 'ZSCAN' => 'static::first',
+ 'HSCAN' => 'static::first',
+ 'PFADD' => 'static::first',
+ 'PFCOUNT' => 'static::all',
+ 'PFMERGE' => 'static::all',
+ 'ZLEXCOUNT' => 'static::first',
+ 'ZRANGEBYLEX' => 'static::first',
+ 'ZREMRANGEBYLEX' => 'static::first',
+ 'ZREVRANGEBYLEX' => 'static::first',
+ 'BITPOS' => 'static::first',
+ /* ---------------- Redis 3.2 ---------------- */
+ 'HSTRLEN' => 'static::first',
+ 'BITFIELD' => 'static::first',
+ 'GEOADD' => 'static::first',
+ 'GEOHASH' => 'static::first',
+ 'GEOPOS' => 'static::first',
+ 'GEODIST' => 'static::first',
+ 'GEORADIUS' => 'static::georadius',
+ 'GEORADIUSBYMEMBER' => 'static::georadius',
+ );
+ }
+
+ /**
+ * Sets a prefix that is applied to all the keys.
+ *
+ * @param string $prefix Prefix for the keys.
+ */
+ public function setPrefix($prefix)
+ {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Gets the current prefix.
+ *
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(CommandInterface $command)
+ {
+ if ($command instanceof PrefixableCommandInterface) {
+ $command->prefixKeys($this->prefix);
+ } elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
+ call_user_func($this->commands[$commandID], $command, $this->prefix);
+ }
+ }
+
+ /**
+ * Sets an handler for the specified command ID.
+ *
+ * The callback signature must have 2 parameters of the following types:
+ *
+ * - Predis\Command\CommandInterface (command instance)
+ * - String (prefix)
+ *
+ * When the callback argument is omitted or NULL, the previously
+ * associated handler for the specified command ID is removed.
+ *
+ * @param string $commandID The ID of the command to be handled.
+ * @param mixed $callback A valid callable object or NULL.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setCommandHandler($commandID, $callback = null)
+ {
+ $commandID = strtoupper($commandID);
+
+ if (!isset($callback)) {
+ unset($this->commands[$commandID]);
+
+ return;
+ }
+
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException(
+ 'Callback must be a valid callable object or NULL'
+ );
+ }
+
+ $this->commands[$commandID] = $callback;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->getPrefix();
+ }
+
+ /**
+ * Applies the specified prefix only the first argument.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function first(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $arguments[0] = "$prefix{$arguments[0]}";
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to all the arguments.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function all(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ foreach ($arguments as &$key) {
+ $key = "$prefix$key";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix only to even arguments in the list.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function interleaved(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $length = count($arguments);
+
+ for ($i = 0; $i < $length; $i += 2) {
+ $arguments[$i] = "$prefix{$arguments[$i]}";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to all the arguments but the first one.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function skipFirst(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $length = count($arguments);
+
+ for ($i = 1; $i < $length; ++$i) {
+ $arguments[$i] = "$prefix{$arguments[$i]}";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to all the arguments but the last one.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function skipLast(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $length = count($arguments);
+
+ for ($i = 0; $i < $length - 1; ++$i) {
+ $arguments[$i] = "$prefix{$arguments[$i]}";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to the keys of a SORT command.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function sort(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $arguments[0] = "$prefix{$arguments[0]}";
+
+ if (($count = count($arguments)) > 1) {
+ for ($i = 1; $i < $count; ++$i) {
+ switch (strtoupper($arguments[$i])) {
+ case 'BY':
+ case 'STORE':
+ $arguments[$i] = "$prefix{$arguments[++$i]}";
+ break;
+
+ case 'GET':
+ $value = $arguments[++$i];
+ if ($value !== '#') {
+ $arguments[$i] = "$prefix$value";
+ }
+ break;
+
+ case 'LIMIT';
+ $i += 2;
+ break;
+ }
+ }
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to the keys of an EVAL-based command.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function evalKeys(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ for ($i = 2; $i < $arguments[1] + 2; ++$i) {
+ $arguments[$i] = "$prefix{$arguments[$i]}";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to the keys of Z[INTERSECTION|UNION]STORE.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function zsetStore(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $arguments[0] = "$prefix{$arguments[0]}";
+ $length = ((int) $arguments[1]) + 2;
+
+ for ($i = 2; $i < $length; ++$i) {
+ $arguments[$i] = "$prefix{$arguments[$i]}";
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to the key of a MIGRATE command.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function migrate(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $arguments[2] = "$prefix{$arguments[2]}";
+ $command->setRawArguments($arguments);
+ }
+ }
+
+ /**
+ * Applies the specified prefix to the key of a GEORADIUS command.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $prefix Prefix string.
+ */
+ public static function georadius(CommandInterface $command, $prefix)
+ {
+ if ($arguments = $command->getArguments()) {
+ $arguments[0] = "$prefix{$arguments[0]}";
+ $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;
+
+ if (($count = count($arguments)) > $startIndex) {
+ for ($i = $startIndex; $i < $count; ++$i) {
+ switch (strtoupper($arguments[$i])) {
+ case 'STORE':
+ case 'STOREDIST':
+ $arguments[$i] = "$prefix{$arguments[++$i]}";
+ break;
+
+ }
+ }
+ }
+
+ $command->setRawArguments($arguments);
+ }
+ }
+}
diff --git a/vendor/predis/predis/src/Command/Processor/ProcessorChain.php b/vendor/predis/predis/src/Command/Processor/ProcessorChain.php
new file mode 100644
index 0000000..95e8ead
--- /dev/null
+++ b/vendor/predis/predis/src/Command/Processor/ProcessorChain.php
@@ -0,0 +1,134 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command\Processor;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Default implementation of a command processors chain.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ProcessorChain implements \ArrayAccess, ProcessorInterface
+{
+ private $processors = array();
+
+ /**
+ * @param array $processors List of instances of ProcessorInterface.
+ */
+ public function __construct($processors = array())
+ {
+ foreach ($processors as $processor) {
+ $this->add($processor);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(ProcessorInterface $processor)
+ {
+ $this->processors[] = $processor;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(ProcessorInterface $processor)
+ {
+ if (false !== $index = array_search($processor, $this->processors, true)) {
+ unset($this[$index]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(CommandInterface $command)
+ {
+ for ($i = 0; $i < $count = count($this->processors); ++$i) {
+ $this->processors[$i]->process($command);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProcessors()
+ {
+ return $this->processors;
+ }
+
+ /**
+ * Returns an iterator over the list of command processor in the chain.
+ *
+ * @return \Traversable<int, ProcessorInterface>
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->processors);
+ }
+
+ /**
+ * Returns the number of command processors in the chain.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->processors);
+ }
+
+ /**
+ * @return bool
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetExists($index)
+ {
+ return isset($this->processors[$index]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($index)
+ {
+ return $this->processors[$index];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetSet($index, $processor)
+ {
+ if (!$processor instanceof ProcessorInterface) {
+ throw new \InvalidArgumentException(
+ 'A processor chain accepts only instances of '.
+ "'Predis\Command\Processor\ProcessorInterface'."
+ );
+ }
+
+ $this->processors[$index] = $processor;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetUnset($index)
+ {
+ unset($this->processors[$index]);
+ $this->processors = array_values($this->processors);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/Processor/ProcessorInterface.php b/vendor/predis/predis/src/Command/Processor/ProcessorInterface.php
new file mode 100644
index 0000000..2f91058
--- /dev/null
+++ b/vendor/predis/predis/src/Command/Processor/ProcessorInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command\Processor;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * A command processor processes Redis commands before they are sent to Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ProcessorInterface
+{
+ /**
+ * Processes the given Redis command.
+ *
+ * @param CommandInterface $command Command instance.
+ */
+ public function process(CommandInterface $command);
+}
diff --git a/vendor/predis/predis/src/Command/PubSubPublish.php b/vendor/predis/predis/src/Command/PubSubPublish.php
new file mode 100644
index 0000000..55508f8
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubPublish.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/publish
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubPublish extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PUBLISH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PubSubPubsub.php b/vendor/predis/predis/src/Command/PubSubPubsub.php
new file mode 100644
index 0000000..8cf8129
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubPubsub.php
@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/pubsub
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubPubsub extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PUBSUB';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ switch (strtolower($this->getArgument(0))) {
+ case 'numsub':
+ return self::processNumsub($data);
+
+ default:
+ return $data;
+ }
+ }
+
+ /**
+ * Returns the processed response to PUBSUB NUMSUB.
+ *
+ * @param array $channels List of channels
+ *
+ * @return array
+ */
+ protected static function processNumsub(array $channels)
+ {
+ $processed = array();
+ $count = count($channels);
+
+ for ($i = 0; $i < $count; ++$i) {
+ $processed[$channels[$i]] = $channels[++$i];
+ }
+
+ return $processed;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PubSubSubscribe.php b/vendor/predis/predis/src/Command/PubSubSubscribe.php
new file mode 100644
index 0000000..e477b31
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubSubscribe.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/subscribe
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubSubscribe extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SUBSCRIBE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PubSubSubscribeByPattern.php b/vendor/predis/predis/src/Command/PubSubSubscribeByPattern.php
new file mode 100644
index 0000000..0118280
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubSubscribeByPattern.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/psubscribe
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubSubscribeByPattern extends PubSubSubscribe
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PSUBSCRIBE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PubSubUnsubscribe.php b/vendor/predis/predis/src/Command/PubSubUnsubscribe.php
new file mode 100644
index 0000000..d57c3ac
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubUnsubscribe.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/unsubscribe
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubUnsubscribe extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'UNSUBSCRIBE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/PubSubUnsubscribeByPattern.php b/vendor/predis/predis/src/Command/PubSubUnsubscribeByPattern.php
new file mode 100644
index 0000000..4d76508
--- /dev/null
+++ b/vendor/predis/predis/src/Command/PubSubUnsubscribeByPattern.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/punsubscribe
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PubSubUnsubscribeByPattern extends PubSubUnsubscribe
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PUNSUBSCRIBE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/RawCommand.php b/vendor/predis/predis/src/Command/RawCommand.php
new file mode 100644
index 0000000..2dd48ca
--- /dev/null
+++ b/vendor/predis/predis/src/Command/RawCommand.php
@@ -0,0 +1,131 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * Class for generic "anonymous" Redis commands.
+ *
+ * This command class does not filter input arguments or parse responses, but
+ * can be used to leverage the standard Predis API to execute any command simply
+ * by providing the needed arguments following the command signature as defined
+ * by Redis in its documentation.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RawCommand implements CommandInterface
+{
+ private $slot;
+ private $commandID;
+ private $arguments;
+
+ /**
+ * @param array $arguments Command ID and its arguments.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(array $arguments)
+ {
+ if (!$arguments) {
+ throw new \InvalidArgumentException(
+ 'The arguments array must contain at least the command ID.'
+ );
+ }
+
+ $this->commandID = strtoupper(array_shift($arguments));
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * Creates a new raw command using a variadic method.
+ *
+ * @param string $commandID Redis command ID.
+ * @param string ... Arguments list for the command.
+ *
+ * @return CommandInterface
+ */
+ public static function create($commandID /* [ $arg, ... */)
+ {
+ $arguments = func_get_args();
+ $command = new self($arguments);
+
+ return $command;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return $this->commandID;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setArguments(array $arguments)
+ {
+ $this->arguments = $arguments;
+ unset($this->slot);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setRawArguments(array $arguments)
+ {
+ $this->setArguments($arguments);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getArguments()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getArgument($index)
+ {
+ if (isset($this->arguments[$index])) {
+ return $this->arguments[$index];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSlot($slot)
+ {
+ $this->slot = $slot;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlot()
+ {
+ if (isset($this->slot)) {
+ return $this->slot;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ScriptCommand.php b/vendor/predis/predis/src/Command/ScriptCommand.php
new file mode 100644
index 0000000..a30bc1d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ScriptCommand.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * Base class used to implement an higher level abstraction for commands based
+ * on Lua scripting with EVAL and EVALSHA.
+ *
+ * @link http://redis.io/commands/eval
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class ScriptCommand extends ServerEvalSHA
+{
+ /**
+ * Gets the body of a Lua script.
+ *
+ * @return string
+ */
+ abstract public function getScript();
+
+ /**
+ * Specifies the number of arguments that should be considered as keys.
+ *
+ * The default behaviour for the base class is to return 0 to indicate that
+ * all the elements of the arguments array should be considered as keys, but
+ * subclasses can enforce a static number of keys.
+ *
+ * @return int
+ */
+ protected function getKeysCount()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the elements from the arguments that are identified as keys.
+ *
+ * @return array
+ */
+ public function getKeys()
+ {
+ return array_slice($this->getArguments(), 2, $this->getKeysCount());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (($numkeys = $this->getKeysCount()) && $numkeys < 0) {
+ $numkeys = count($arguments) + $numkeys;
+ }
+
+ return array_merge(array(sha1($this->getScript()), (int) $numkeys), $arguments);
+ }
+
+ /**
+ * @return array
+ */
+ public function getEvalArguments()
+ {
+ $arguments = $this->getArguments();
+ $arguments[0] = $this->getScript();
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerBackgroundRewriteAOF.php b/vendor/predis/predis/src/Command/ServerBackgroundRewriteAOF.php
new file mode 100644
index 0000000..c66a294
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerBackgroundRewriteAOF.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bgrewriteaof
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerBackgroundRewriteAOF extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BGREWRITEAOF';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ return $data == 'Background append only file rewriting started';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerBackgroundSave.php b/vendor/predis/predis/src/Command/ServerBackgroundSave.php
new file mode 100644
index 0000000..4bf67ef
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerBackgroundSave.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bgsave
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerBackgroundSave extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BGSAVE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ return $data === 'Background saving started' ? true : $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerClient.php b/vendor/predis/predis/src/Command/ServerClient.php
new file mode 100644
index 0000000..d00ebbf
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerClient.php
@@ -0,0 +1,74 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/client-list
+ * @link http://redis.io/commands/client-kill
+ * @link http://redis.io/commands/client-getname
+ * @link http://redis.io/commands/client-setname
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerClient extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'CLIENT';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ $args = array_change_key_case($this->getArguments(), CASE_UPPER);
+
+ switch (strtoupper($args[0])) {
+ case 'LIST':
+ return $this->parseClientList($data);
+ case 'KILL':
+ case 'GETNAME':
+ case 'SETNAME':
+ default:
+ return $data;
+ }
+ }
+
+ /**
+ * Parses the response to CLIENT LIST and returns a structured list.
+ *
+ * @param string $data Response buffer.
+ *
+ * @return array
+ */
+ protected function parseClientList($data)
+ {
+ $clients = array();
+
+ foreach (explode("\n", $data, -1) as $clientData) {
+ $client = array();
+
+ foreach (explode(' ', $clientData) as $kv) {
+ @list($k, $v) = explode('=', $kv);
+ $client[$k] = $v;
+ }
+
+ $clients[] = $client;
+ }
+
+ return $clients;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerCommand.php b/vendor/predis/predis/src/Command/ServerCommand.php
new file mode 100644
index 0000000..e9b3393
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerCommand.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/command
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerCommand extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'COMMAND';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerConfig.php b/vendor/predis/predis/src/Command/ServerConfig.php
new file mode 100644
index 0000000..81e497a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerConfig.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/config-set
+ * @link http://redis.io/commands/config-get
+ * @link http://redis.io/commands/config-resetstat
+ * @link http://redis.io/commands/config-rewrite
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerConfig extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'CONFIG';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if (is_array($data)) {
+ $result = array();
+
+ for ($i = 0; $i < count($data); ++$i) {
+ $result[$data[$i]] = $data[++$i];
+ }
+
+ return $result;
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerDatabaseSize.php b/vendor/predis/predis/src/Command/ServerDatabaseSize.php
new file mode 100644
index 0000000..6bc8972
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerDatabaseSize.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/dbsize
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerDatabaseSize extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DBSIZE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerEval.php b/vendor/predis/predis/src/Command/ServerEval.php
new file mode 100644
index 0000000..f5eefd8
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerEval.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/eval
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerEval extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EVAL';
+ }
+
+ /**
+ * Calculates the SHA1 hash of the body of the script.
+ *
+ * @return string SHA1 hash.
+ */
+ public function getScriptHash()
+ {
+ return sha1($this->getArgument(0));
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerEvalSHA.php b/vendor/predis/predis/src/Command/ServerEvalSHA.php
new file mode 100644
index 0000000..520a8e9
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerEvalSHA.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/evalsha
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerEvalSHA extends ServerEval
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EVALSHA';
+ }
+
+ /**
+ * Returns the SHA1 hash of the body of the script.
+ *
+ * @return string SHA1 hash.
+ */
+ public function getScriptHash()
+ {
+ return $this->getArgument(0);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerFlushAll.php b/vendor/predis/predis/src/Command/ServerFlushAll.php
new file mode 100644
index 0000000..c35b2ad
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerFlushAll.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/flushall
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerFlushAll extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'FLUSHALL';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerFlushDatabase.php b/vendor/predis/predis/src/Command/ServerFlushDatabase.php
new file mode 100644
index 0000000..3da6b32
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerFlushDatabase.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/flushdb
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerFlushDatabase extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'FLUSHDB';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerInfo.php b/vendor/predis/predis/src/Command/ServerInfo.php
new file mode 100644
index 0000000..96d6ada
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerInfo.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/info
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerInfo extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'INFO';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ $info = array();
+ $infoLines = preg_split('/\r?\n/', $data);
+
+ foreach ($infoLines as $row) {
+ if (strpos($row, ':') === false) {
+ continue;
+ }
+
+ list($k, $v) = $this->parseRow($row);
+ $info[$k] = $v;
+ }
+
+ return $info;
+ }
+
+ /**
+ * Parses a single row of the response and returns the key-value pair.
+ *
+ * @param string $row Single row of the response.
+ *
+ * @return array
+ */
+ protected function parseRow($row)
+ {
+ list($k, $v) = explode(':', $row, 2);
+
+ if (preg_match('/^db\d+$/', $k)) {
+ $v = $this->parseDatabaseStats($v);
+ }
+
+ return array($k, $v);
+ }
+
+ /**
+ * Extracts the statistics of each logical DB from the string buffer.
+ *
+ * @param string $str Response buffer.
+ *
+ * @return array
+ */
+ protected function parseDatabaseStats($str)
+ {
+ $db = array();
+
+ foreach (explode(',', $str) as $dbvar) {
+ list($dbvk, $dbvv) = explode('=', $dbvar);
+ $db[trim($dbvk)] = $dbvv;
+ }
+
+ return $db;
+ }
+
+ /**
+ * Parses the response and extracts the allocation statistics.
+ *
+ * @param string $str Response buffer.
+ *
+ * @return array
+ */
+ protected function parseAllocationStats($str)
+ {
+ $stats = array();
+
+ foreach (explode(',', $str) as $kv) {
+ @list($size, $objects, $extra) = explode('=', $kv);
+
+ // hack to prevent incorrect values when parsing the >=256 key
+ if (isset($extra)) {
+ $size = ">=$objects";
+ $objects = $extra;
+ }
+
+ $stats[$size] = $objects;
+ }
+
+ return $stats;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerInfoV26x.php b/vendor/predis/predis/src/Command/ServerInfoV26x.php
new file mode 100644
index 0000000..90c9b71
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerInfoV26x.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/info
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerInfoV26x extends ServerInfo
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if ($data === '') {
+ return array();
+ }
+
+ $info = array();
+
+ $current = null;
+ $infoLines = preg_split('/\r?\n/', $data);
+
+ if (isset($infoLines[0]) && $infoLines[0][0] !== '#') {
+ return parent::parseResponse($data);
+ }
+
+ foreach ($infoLines as $row) {
+ if ($row === '') {
+ continue;
+ }
+
+ if (preg_match('/^# (\w+)$/', $row, $matches)) {
+ $info[$matches[1]] = array();
+ $current = &$info[$matches[1]];
+ continue;
+ }
+
+ list($k, $v) = $this->parseRow($row);
+ $current[$k] = $v;
+ }
+
+ return $info;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerLastSave.php b/vendor/predis/predis/src/Command/ServerLastSave.php
new file mode 100644
index 0000000..feeb19a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerLastSave.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/lastsave
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerLastSave extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'LASTSAVE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerMonitor.php b/vendor/predis/predis/src/Command/ServerMonitor.php
new file mode 100644
index 0000000..1c3d330
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerMonitor.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/monitor
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerMonitor extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MONITOR';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerObject.php b/vendor/predis/predis/src/Command/ServerObject.php
new file mode 100644
index 0000000..f921701
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerObject.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/object
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerObject extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'OBJECT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerSave.php b/vendor/predis/predis/src/Command/ServerSave.php
new file mode 100644
index 0000000..addefe2
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerSave.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/save
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerSave extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SAVE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerScript.php b/vendor/predis/predis/src/Command/ServerScript.php
new file mode 100644
index 0000000..7a01018
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerScript.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/script
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerScript extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SCRIPT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerSentinel.php b/vendor/predis/predis/src/Command/ServerSentinel.php
new file mode 100644
index 0000000..bef2316
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerSentinel.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/topics/sentinel
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerSentinel extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SENTINEL';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ $argument = $this->getArgument(0);
+ $argument = is_null($argument) ? null : strtolower($argument);
+
+ switch ($argument) {
+ case 'masters':
+ case 'slaves':
+ return self::processMastersOrSlaves($data);
+
+ default:
+ return $data;
+ }
+ }
+
+ /**
+ * Returns a processed response to SENTINEL MASTERS or SENTINEL SLAVES.
+ *
+ * @param array $servers List of Redis servers.
+ *
+ * @return array
+ */
+ protected static function processMastersOrSlaves(array $servers)
+ {
+ foreach ($servers as $idx => $node) {
+ $processed = array();
+ $count = count($node);
+
+ for ($i = 0; $i < $count; ++$i) {
+ $processed[$node[$i]] = $node[++$i];
+ }
+
+ $servers[$idx] = $processed;
+ }
+
+ return $servers;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerShutdown.php b/vendor/predis/predis/src/Command/ServerShutdown.php
new file mode 100644
index 0000000..f5b745a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerShutdown.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/shutdown
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerShutdown extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SHUTDOWN';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerSlaveOf.php b/vendor/predis/predis/src/Command/ServerSlaveOf.php
new file mode 100644
index 0000000..4ff4455
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerSlaveOf.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/slaveof
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerSlaveOf extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SLAVEOF';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 0 || $arguments[0] === 'NO ONE') {
+ return array('NO', 'ONE');
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerSlowlog.php b/vendor/predis/predis/src/Command/ServerSlowlog.php
new file mode 100644
index 0000000..137ff59
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerSlowlog.php
@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/slowlog
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerSlowlog extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SLOWLOG';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if (is_array($data)) {
+ $log = array();
+
+ foreach ($data as $index => $entry) {
+ $log[$index] = array(
+ 'id' => $entry[0],
+ 'timestamp' => $entry[1],
+ 'duration' => $entry[2],
+ 'command' => $entry[3],
+ );
+ }
+
+ return $log;
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ServerTime.php b/vendor/predis/predis/src/Command/ServerTime.php
new file mode 100644
index 0000000..589f92c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ServerTime.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/time
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerTime extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'TIME';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetAdd.php b/vendor/predis/predis/src/Command/SetAdd.php
new file mode 100644
index 0000000..c118818
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetAdd.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sadd
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetAdd extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SADD';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetCardinality.php b/vendor/predis/predis/src/Command/SetCardinality.php
new file mode 100644
index 0000000..a9f959b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetCardinality.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/scard
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetCardinality extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SCARD';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetDifference.php b/vendor/predis/predis/src/Command/SetDifference.php
new file mode 100644
index 0000000..35f23f9
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetDifference.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sdiff
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetDifference extends SetIntersection
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SDIFF';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetDifferenceStore.php b/vendor/predis/predis/src/Command/SetDifferenceStore.php
new file mode 100644
index 0000000..0cb7815
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetDifferenceStore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sdiffstore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetDifferenceStore extends SetIntersectionStore
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SDIFFSTORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetIntersection.php b/vendor/predis/predis/src/Command/SetIntersection.php
new file mode 100644
index 0000000..d18258f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetIntersection.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sinter
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetIntersection extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SINTER';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetIntersectionStore.php b/vendor/predis/predis/src/Command/SetIntersectionStore.php
new file mode 100644
index 0000000..b748618
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetIntersectionStore.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sinterstore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetIntersectionStore extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SINTERSTORE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 2 && is_array($arguments[1])) {
+ return array_merge(array($arguments[0]), $arguments[1]);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetIsMember.php b/vendor/predis/predis/src/Command/SetIsMember.php
new file mode 100644
index 0000000..7742522
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetIsMember.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sismember
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetIsMember extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SISMEMBER';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetMembers.php b/vendor/predis/predis/src/Command/SetMembers.php
new file mode 100644
index 0000000..f4076ae
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetMembers.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/smembers
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetMembers extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SMEMBERS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetMove.php b/vendor/predis/predis/src/Command/SetMove.php
new file mode 100644
index 0000000..edd4e51
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetMove.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/smove
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetMove extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SMOVE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetPop.php b/vendor/predis/predis/src/Command/SetPop.php
new file mode 100644
index 0000000..b78d3f3
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetPop.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/spop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetPop extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SPOP';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetRandomMember.php b/vendor/predis/predis/src/Command/SetRandomMember.php
new file mode 100644
index 0000000..2cb79a0
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetRandomMember.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/srandmember
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetRandomMember extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SRANDMEMBER';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetRemove.php b/vendor/predis/predis/src/Command/SetRemove.php
new file mode 100644
index 0000000..b34710c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetRemove.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/srem
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetRemove extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SREM';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetScan.php b/vendor/predis/predis/src/Command/SetScan.php
new file mode 100644
index 0000000..d42b28d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetScan.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sscan
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetScan extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SSCAN';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 3 && is_array($arguments[2])) {
+ $options = $this->prepareOptions(array_pop($arguments));
+ $arguments = array_merge($arguments, $options);
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ protected function prepareOptions($options)
+ {
+ $options = array_change_key_case($options, CASE_UPPER);
+ $normalized = array();
+
+ if (!empty($options['MATCH'])) {
+ $normalized[] = 'MATCH';
+ $normalized[] = $options['MATCH'];
+ }
+
+ if (!empty($options['COUNT'])) {
+ $normalized[] = 'COUNT';
+ $normalized[] = $options['COUNT'];
+ }
+
+ return $normalized;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetUnion.php b/vendor/predis/predis/src/Command/SetUnion.php
new file mode 100644
index 0000000..7da842b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetUnion.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sunion
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetUnion extends SetIntersection
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SUNION';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/SetUnionStore.php b/vendor/predis/predis/src/Command/SetUnionStore.php
new file mode 100644
index 0000000..eac821a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/SetUnionStore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/sunionstore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class SetUnionStore extends SetIntersectionStore
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SUNIONSTORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringAppend.php b/vendor/predis/predis/src/Command/StringAppend.php
new file mode 100644
index 0000000..dac8b84
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringAppend.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/append
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringAppend extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'APPEND';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringBitCount.php b/vendor/predis/predis/src/Command/StringBitCount.php
new file mode 100644
index 0000000..193cce9
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringBitCount.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bitcount
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringBitCount extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BITCOUNT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringBitField.php b/vendor/predis/predis/src/Command/StringBitField.php
new file mode 100644
index 0000000..9f4deaa
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringBitField.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bitfield
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringBitField extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BITFIELD';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringBitOp.php b/vendor/predis/predis/src/Command/StringBitOp.php
new file mode 100644
index 0000000..e04ee79
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringBitOp.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bitop
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringBitOp extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BITOP';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 3 && is_array($arguments[2])) {
+ list($operation, $destination) = $arguments;
+ $arguments = $arguments[2];
+ array_unshift($arguments, $operation, $destination);
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringBitPos.php b/vendor/predis/predis/src/Command/StringBitPos.php
new file mode 100644
index 0000000..4295766
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringBitPos.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/bitpos
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringBitPos extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'BITPOS';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringDecrement.php b/vendor/predis/predis/src/Command/StringDecrement.php
new file mode 100644
index 0000000..aa5808c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringDecrement.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/decr
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringDecrement extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DECR';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringDecrementBy.php b/vendor/predis/predis/src/Command/StringDecrementBy.php
new file mode 100644
index 0000000..cbf3e11
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringDecrementBy.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/decrby
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringDecrementBy extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DECRBY';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringGet.php b/vendor/predis/predis/src/Command/StringGet.php
new file mode 100644
index 0000000..138e915
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringGet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/get
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringGet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringGetBit.php b/vendor/predis/predis/src/Command/StringGetBit.php
new file mode 100644
index 0000000..3c5b4f9
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringGetBit.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/getbit
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringGetBit extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GETBIT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringGetMultiple.php b/vendor/predis/predis/src/Command/StringGetMultiple.php
new file mode 100644
index 0000000..e340f9c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringGetMultiple.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/mget
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringGetMultiple extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MGET';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeArguments($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringGetRange.php b/vendor/predis/predis/src/Command/StringGetRange.php
new file mode 100644
index 0000000..bb10565
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringGetRange.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/getrange
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringGetRange extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GETRANGE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringGetSet.php b/vendor/predis/predis/src/Command/StringGetSet.php
new file mode 100644
index 0000000..b68870d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringGetSet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/getset
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringGetSet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'GETSET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringIncrement.php b/vendor/predis/predis/src/Command/StringIncrement.php
new file mode 100644
index 0000000..fa1846e
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringIncrement.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/incr
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringIncrement extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'INCR';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringIncrementBy.php b/vendor/predis/predis/src/Command/StringIncrementBy.php
new file mode 100644
index 0000000..9d8241a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringIncrementBy.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/incrby
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringIncrementBy extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'INCRBY';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringIncrementByFloat.php b/vendor/predis/predis/src/Command/StringIncrementByFloat.php
new file mode 100644
index 0000000..164a086
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringIncrementByFloat.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/incrbyfloat
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringIncrementByFloat extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'INCRBYFLOAT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringPreciseSetExpire.php b/vendor/predis/predis/src/Command/StringPreciseSetExpire.php
new file mode 100644
index 0000000..2faa954
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringPreciseSetExpire.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/psetex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringPreciseSetExpire extends StringSetExpire
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'PSETEX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSet.php b/vendor/predis/predis/src/Command/StringSet.php
new file mode 100644
index 0000000..b146994
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSet.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/set
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSet extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SET';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetBit.php b/vendor/predis/predis/src/Command/StringSetBit.php
new file mode 100644
index 0000000..7933b6b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetBit.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/setbit
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetBit extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SETBIT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetExpire.php b/vendor/predis/predis/src/Command/StringSetExpire.php
new file mode 100644
index 0000000..f088170
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetExpire.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/setex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetExpire extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SETEX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetMultiple.php b/vendor/predis/predis/src/Command/StringSetMultiple.php
new file mode 100644
index 0000000..a3c5324
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetMultiple.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/mset
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetMultiple extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MSET';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 1 && is_array($arguments[0])) {
+ $flattenedKVs = array();
+ $args = $arguments[0];
+
+ foreach ($args as $k => $v) {
+ $flattenedKVs[] = $k;
+ $flattenedKVs[] = $v;
+ }
+
+ return $flattenedKVs;
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetMultiplePreserve.php b/vendor/predis/predis/src/Command/StringSetMultiplePreserve.php
new file mode 100644
index 0000000..b46a88c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetMultiplePreserve.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/msetnx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetMultiplePreserve extends StringSetMultiple
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MSETNX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetPreserve.php b/vendor/predis/predis/src/Command/StringSetPreserve.php
new file mode 100644
index 0000000..e89c974
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetPreserve.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/setnx
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetPreserve extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SETNX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSetRange.php b/vendor/predis/predis/src/Command/StringSetRange.php
new file mode 100644
index 0000000..4d9389f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSetRange.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/setrange
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSetRange extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SETRANGE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringStrlen.php b/vendor/predis/predis/src/Command/StringStrlen.php
new file mode 100644
index 0000000..10f492f
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringStrlen.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/strlen
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringStrlen extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'STRLEN';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/StringSubstr.php b/vendor/predis/predis/src/Command/StringSubstr.php
new file mode 100644
index 0000000..3aab7ad
--- /dev/null
+++ b/vendor/predis/predis/src/Command/StringSubstr.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/substr
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StringSubstr extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'SUBSTR';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/TransactionDiscard.php b/vendor/predis/predis/src/Command/TransactionDiscard.php
new file mode 100644
index 0000000..44aca2b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/TransactionDiscard.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/discard
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class TransactionDiscard extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'DISCARD';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/TransactionExec.php b/vendor/predis/predis/src/Command/TransactionExec.php
new file mode 100644
index 0000000..dbd81aa
--- /dev/null
+++ b/vendor/predis/predis/src/Command/TransactionExec.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/exec
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class TransactionExec extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'EXEC';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/TransactionMulti.php b/vendor/predis/predis/src/Command/TransactionMulti.php
new file mode 100644
index 0000000..673bf55
--- /dev/null
+++ b/vendor/predis/predis/src/Command/TransactionMulti.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/multi
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class TransactionMulti extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'MULTI';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/TransactionUnwatch.php b/vendor/predis/predis/src/Command/TransactionUnwatch.php
new file mode 100644
index 0000000..7925554
--- /dev/null
+++ b/vendor/predis/predis/src/Command/TransactionUnwatch.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/unwatch
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class TransactionUnwatch extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'UNWATCH';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/TransactionWatch.php b/vendor/predis/predis/src/Command/TransactionWatch.php
new file mode 100644
index 0000000..d360780
--- /dev/null
+++ b/vendor/predis/predis/src/Command/TransactionWatch.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/watch
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class TransactionWatch extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'WATCH';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (isset($arguments[0]) && is_array($arguments[0])) {
+ return $arguments[0];
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetAdd.php b/vendor/predis/predis/src/Command/ZSetAdd.php
new file mode 100644
index 0000000..55e4729
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetAdd.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zadd
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetAdd extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZADD';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (is_array(end($arguments))) {
+ foreach (array_pop($arguments) as $member => $score) {
+ $arguments[] = $score;
+ $arguments[] = $member;
+ }
+ }
+
+ return $arguments;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetCardinality.php b/vendor/predis/predis/src/Command/ZSetCardinality.php
new file mode 100644
index 0000000..1033200
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetCardinality.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zcard
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetCardinality extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZCARD';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetCount.php b/vendor/predis/predis/src/Command/ZSetCount.php
new file mode 100644
index 0000000..918bd2b
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetCount.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zcount
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetCount extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZCOUNT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetIncrementBy.php b/vendor/predis/predis/src/Command/ZSetIncrementBy.php
new file mode 100644
index 0000000..245a8e0
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetIncrementBy.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zincrby
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetIncrementBy extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZINCRBY';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetIntersectionStore.php b/vendor/predis/predis/src/Command/ZSetIntersectionStore.php
new file mode 100644
index 0000000..572a7a3
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetIntersectionStore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zinterstore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetIntersectionStore extends ZSetUnionStore
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZINTERSTORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetLexCount.php b/vendor/predis/predis/src/Command/ZSetLexCount.php
new file mode 100644
index 0000000..447b8eb
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetLexCount.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zlexcount
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetLexCount extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZLEXCOUNT';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRange.php b/vendor/predis/predis/src/Command/ZSetRange.php
new file mode 100644
index 0000000..ce72c7c
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRange.php
@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrange
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRange extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZRANGE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 4) {
+ $lastType = gettype($arguments[3]);
+
+ if ($lastType === 'string' && strtoupper($arguments[3]) === 'WITHSCORES') {
+ // Used for compatibility with older versions
+ $arguments[3] = array('WITHSCORES' => true);
+ $lastType = 'array';
+ }
+
+ if ($lastType === 'array') {
+ $options = $this->prepareOptions(array_pop($arguments));
+
+ return array_merge($arguments, $options);
+ }
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ protected function prepareOptions($options)
+ {
+ $opts = array_change_key_case($options, CASE_UPPER);
+ $finalizedOpts = array();
+
+ if (!empty($opts['WITHSCORES'])) {
+ $finalizedOpts[] = 'WITHSCORES';
+ }
+
+ return $finalizedOpts;
+ }
+
+ /**
+ * Checks for the presence of the WITHSCORES modifier.
+ *
+ * @return bool
+ */
+ protected function withScores()
+ {
+ $arguments = $this->getArguments();
+
+ if (count($arguments) < 4) {
+ return false;
+ }
+
+ return strtoupper($arguments[3]) === 'WITHSCORES';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if ($this->withScores()) {
+ $result = array();
+
+ for ($i = 0; $i < count($data); ++$i) {
+ $result[$data[$i]] = $data[++$i];
+ }
+
+ return $result;
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRangeByLex.php b/vendor/predis/predis/src/Command/ZSetRangeByLex.php
new file mode 100644
index 0000000..9b2991a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRangeByLex.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrangebylex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRangeByLex extends ZSetRange
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZRANGEBYLEX';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function prepareOptions($options)
+ {
+ $opts = array_change_key_case($options, CASE_UPPER);
+ $finalizedOpts = array();
+
+ if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
+ $limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);
+
+ $finalizedOpts[] = 'LIMIT';
+ $finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
+ $finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
+ }
+
+ return $finalizedOpts;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function withScores()
+ {
+ return false;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRangeByScore.php b/vendor/predis/predis/src/Command/ZSetRangeByScore.php
new file mode 100644
index 0000000..961a5bc
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRangeByScore.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrangebyscore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRangeByScore extends ZSetRange
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZRANGEBYSCORE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function prepareOptions($options)
+ {
+ $opts = array_change_key_case($options, CASE_UPPER);
+ $finalizedOpts = array();
+
+ if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
+ $limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);
+
+ $finalizedOpts[] = 'LIMIT';
+ $finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
+ $finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
+ }
+
+ return array_merge($finalizedOpts, parent::prepareOptions($options));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function withScores()
+ {
+ $arguments = $this->getArguments();
+
+ for ($i = 3; $i < count($arguments); ++$i) {
+ switch (strtoupper($arguments[$i])) {
+ case 'WITHSCORES':
+ return true;
+
+ case 'LIMIT':
+ $i += 2;
+ break;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRank.php b/vendor/predis/predis/src/Command/ZSetRank.php
new file mode 100644
index 0000000..d0c9c53
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRank.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrank
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRank extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZRANK';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRemove.php b/vendor/predis/predis/src/Command/ZSetRemove.php
new file mode 100644
index 0000000..cd8ada0
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRemove.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrem
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRemove extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREM';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ return self::normalizeVariadic($arguments);
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRemoveRangeByLex.php b/vendor/predis/predis/src/Command/ZSetRemoveRangeByLex.php
new file mode 100644
index 0000000..9ea2d9e
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRemoveRangeByLex.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zremrangebylex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRemoveRangeByLex extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREMRANGEBYLEX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRemoveRangeByRank.php b/vendor/predis/predis/src/Command/ZSetRemoveRangeByRank.php
new file mode 100644
index 0000000..89cd5ba
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRemoveRangeByRank.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zremrangebyrank
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRemoveRangeByRank extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREMRANGEBYRANK';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetRemoveRangeByScore.php b/vendor/predis/predis/src/Command/ZSetRemoveRangeByScore.php
new file mode 100644
index 0000000..a7c3081
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetRemoveRangeByScore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zremrangebyscore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetRemoveRangeByScore extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREMRANGEBYSCORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetReverseRange.php b/vendor/predis/predis/src/Command/ZSetReverseRange.php
new file mode 100644
index 0000000..6a46a7a
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetReverseRange.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrevrange
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetReverseRange extends ZSetRange
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREVRANGE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetReverseRangeByLex.php b/vendor/predis/predis/src/Command/ZSetReverseRangeByLex.php
new file mode 100644
index 0000000..5dd611d
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetReverseRangeByLex.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrevrangebylex
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetReverseRangeByLex extends ZSetRangeByLex
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREVRANGEBYLEX';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetReverseRangeByScore.php b/vendor/predis/predis/src/Command/ZSetReverseRangeByScore.php
new file mode 100644
index 0000000..1078eb7
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetReverseRangeByScore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrevrangebyscore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetReverseRangeByScore extends ZSetRangeByScore
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREVRANGEBYSCORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetReverseRank.php b/vendor/predis/predis/src/Command/ZSetReverseRank.php
new file mode 100644
index 0000000..33fb815
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetReverseRank.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zrevrank
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetReverseRank extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZREVRANK';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetScan.php b/vendor/predis/predis/src/Command/ZSetScan.php
new file mode 100644
index 0000000..1dc2352
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetScan.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zscan
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetScan extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZSCAN';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ if (count($arguments) === 3 && is_array($arguments[2])) {
+ $options = $this->prepareOptions(array_pop($arguments));
+ $arguments = array_merge($arguments, $options);
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ protected function prepareOptions($options)
+ {
+ $options = array_change_key_case($options, CASE_UPPER);
+ $normalized = array();
+
+ if (!empty($options['MATCH'])) {
+ $normalized[] = 'MATCH';
+ $normalized[] = $options['MATCH'];
+ }
+
+ if (!empty($options['COUNT'])) {
+ $normalized[] = 'COUNT';
+ $normalized[] = $options['COUNT'];
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parseResponse($data)
+ {
+ if (is_array($data)) {
+ $members = $data[1];
+ $result = array();
+
+ for ($i = 0; $i < count($members); ++$i) {
+ $result[$members[$i]] = (float) $members[++$i];
+ }
+
+ $data[1] = $result;
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetScore.php b/vendor/predis/predis/src/Command/ZSetScore.php
new file mode 100644
index 0000000..2e7fce8
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetScore.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zscore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetScore extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZSCORE';
+ }
+}
diff --git a/vendor/predis/predis/src/Command/ZSetUnionStore.php b/vendor/predis/predis/src/Command/ZSetUnionStore.php
new file mode 100644
index 0000000..befc5ce
--- /dev/null
+++ b/vendor/predis/predis/src/Command/ZSetUnionStore.php
@@ -0,0 +1,78 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Command;
+
+/**
+ * @link http://redis.io/commands/zunionstore
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ZSetUnionStore extends Command
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ return 'ZUNIONSTORE';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function filterArguments(array $arguments)
+ {
+ $options = array();
+ $argc = count($arguments);
+
+ if ($argc > 2 && is_array($arguments[$argc - 1])) {
+ $options = $this->prepareOptions(array_pop($arguments));
+ }
+
+ if (is_array($arguments[1])) {
+ $arguments = array_merge(
+ array($arguments[0], count($arguments[1])),
+ $arguments[1]
+ );
+ }
+
+ return array_merge($arguments, $options);
+ }
+
+ /**
+ * Returns a list of options and modifiers compatible with Redis.
+ *
+ * @param array $options List of options.
+ *
+ * @return array
+ */
+ private function prepareOptions($options)
+ {
+ $opts = array_change_key_case($options, CASE_UPPER);
+ $finalizedOpts = array();
+
+ if (isset($opts['WEIGHTS']) && is_array($opts['WEIGHTS'])) {
+ $finalizedOpts[] = 'WEIGHTS';
+
+ foreach ($opts['WEIGHTS'] as $weight) {
+ $finalizedOpts[] = $weight;
+ }
+ }
+
+ if (isset($opts['AGGREGATE'])) {
+ $finalizedOpts[] = 'AGGREGATE';
+ $finalizedOpts[] = $opts['AGGREGATE'];
+ }
+
+ return $finalizedOpts;
+ }
+}
diff --git a/vendor/predis/predis/src/CommunicationException.php b/vendor/predis/predis/src/CommunicationException.php
new file mode 100644
index 0000000..6b7f6a2
--- /dev/null
+++ b/vendor/predis/predis/src/CommunicationException.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+use Predis\Connection\NodeConnectionInterface;
+
+/**
+ * Base exception class for network-related errors.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class CommunicationException extends PredisException
+{
+ private $connection;
+
+ /**
+ * @param NodeConnectionInterface $connection Connection that generated the exception.
+ * @param string $message Error message.
+ * @param int $code Error code.
+ * @param \Exception $innerException Inner exception for wrapping the original error.
+ */
+ public function __construct(
+ NodeConnectionInterface $connection,
+ $message = null,
+ $code = null,
+ \Exception $innerException = null
+ ) {
+ parent::__construct(
+ is_null($message) ? '' : $message,
+ is_null($code) ? 0 : $code,
+ $innerException
+ );
+
+ $this->connection = $connection;
+ }
+
+ /**
+ * Gets the connection that generated the exception.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getConnection()
+ {
+ return $this->connection;
+ }
+
+ /**
+ * Indicates if the receiver should reset the underlying connection.
+ *
+ * @return bool
+ */
+ public function shouldResetConnection()
+ {
+ return true;
+ }
+
+ /**
+ * Helper method to handle exceptions generated by a connection object.
+ *
+ * @param CommunicationException $exception Exception.
+ *
+ * @throws CommunicationException
+ */
+ public static function handle(CommunicationException $exception)
+ {
+ if ($exception->shouldResetConnection()) {
+ $connection = $exception->getConnection();
+
+ if ($connection->isConnected()) {
+ $connection->disconnect();
+ }
+ }
+
+ throw $exception;
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/ClusterOption.php b/vendor/predis/predis/src/Configuration/ClusterOption.php
new file mode 100644
index 0000000..69e36de
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/ClusterOption.php
@@ -0,0 +1,76 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\Aggregate\PredisCluster;
+use Predis\Connection\Aggregate\RedisCluster;
+
+/**
+ * Configures an aggregate connection used for clustering
+ * multiple Redis nodes using various implementations with
+ * different algorithms or strategies.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ClusterOption implements OptionInterface
+{
+ /**
+ * Creates a new cluster connection from on a known descriptive name.
+ *
+ * @param OptionsInterface $options Instance of the client options.
+ * @param string $id Descriptive identifier of the cluster type (`predis`, `redis-cluster`)
+ *
+ * @return ClusterInterface|null
+ */
+ protected function createByDescription(OptionsInterface $options, $id)
+ {
+ switch ($id) {
+ case 'predis':
+ case 'predis-cluster':
+ return new PredisCluster();
+
+ case 'redis':
+ case 'redis-cluster':
+ return new RedisCluster($options->connections);
+
+ default:
+ return;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ if (is_string($value)) {
+ $value = $this->createByDescription($options, $value);
+ }
+
+ if (!$value instanceof ClusterInterface) {
+ throw new \InvalidArgumentException(
+ "An instance of type 'Predis\Connection\Aggregate\ClusterInterface' was expected."
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ return new PredisCluster();
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/ConnectionFactoryOption.php b/vendor/predis/predis/src/Configuration/ConnectionFactoryOption.php
new file mode 100644
index 0000000..bf8479c
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/ConnectionFactoryOption.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Connection\Factory;
+use Predis\Connection\FactoryInterface;
+
+/**
+ * Configures a connection factory used by the client to create new connection
+ * instances for single Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionFactoryOption implements OptionInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ if ($value instanceof FactoryInterface) {
+ return $value;
+ } elseif (is_array($value)) {
+ $factory = $this->getDefault($options);
+
+ foreach ($value as $scheme => $initializer) {
+ $factory->define($scheme, $initializer);
+ }
+
+ return $factory;
+ } else {
+ throw new \InvalidArgumentException(
+ 'Invalid value provided for the connections option.'
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ $factory = new Factory();
+
+ if ($options->defined('parameters')) {
+ $factory->setDefaultParameters($options->parameters);
+ }
+
+ return $factory;
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/ExceptionsOption.php b/vendor/predis/predis/src/Configuration/ExceptionsOption.php
new file mode 100644
index 0000000..337733e
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/ExceptionsOption.php
@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+/**
+ * Configures whether consumers (such as the client) should throw exceptions on
+ * Redis errors (-ERR responses) or just return instances of error responses.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ExceptionsOption implements OptionInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ return filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ return true;
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/OptionInterface.php b/vendor/predis/predis/src/Configuration/OptionInterface.php
new file mode 100644
index 0000000..b31e0c9
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/OptionInterface.php
@@ -0,0 +1,40 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+/**
+ * Defines an handler used by Predis\Configuration\Options to filter, validate
+ * or return default values for a given option.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface OptionInterface
+{
+ /**
+ * Filters and validates the passed value.
+ *
+ * @param OptionsInterface $options Options container.
+ * @param mixed $value Input value.
+ *
+ * @return mixed
+ */
+ public function filter(OptionsInterface $options, $value);
+
+ /**
+ * Returns the default value for the option.
+ *
+ * @param OptionsInterface $options Options container.
+ *
+ * @return mixed
+ */
+ public function getDefault(OptionsInterface $options);
+}
diff --git a/vendor/predis/predis/src/Configuration/Options.php b/vendor/predis/predis/src/Configuration/Options.php
new file mode 100644
index 0000000..c17dd54
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/Options.php
@@ -0,0 +1,122 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+/**
+ * Manages Predis options with filtering, conversion and lazy initialization of
+ * values using a mini-DI container approach.
+ *
+ * {@inheritdoc}
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Options implements OptionsInterface
+{
+ protected $input;
+ protected $options;
+ protected $handlers;
+
+ /**
+ * @param array $options Array of options with their values
+ */
+ public function __construct(array $options = array())
+ {
+ $this->input = $options;
+ $this->options = array();
+ $this->handlers = $this->getHandlers();
+ }
+
+ /**
+ * Ensures that the default options are initialized.
+ *
+ * @return array
+ */
+ protected function getHandlers()
+ {
+ return array(
+ 'cluster' => 'Predis\Configuration\ClusterOption',
+ 'connections' => 'Predis\Configuration\ConnectionFactoryOption',
+ 'exceptions' => 'Predis\Configuration\ExceptionsOption',
+ 'prefix' => 'Predis\Configuration\PrefixOption',
+ 'profile' => 'Predis\Configuration\ProfileOption',
+ 'replication' => 'Predis\Configuration\ReplicationOption',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault($option)
+ {
+ if (isset($this->handlers[$option])) {
+ $handler = $this->handlers[$option];
+ $handler = new $handler();
+
+ return $handler->getDefault($this);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function defined($option)
+ {
+ return
+ array_key_exists($option, $this->options) ||
+ array_key_exists($option, $this->input)
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __isset($option)
+ {
+ return (
+ array_key_exists($option, $this->options) ||
+ array_key_exists($option, $this->input)
+ ) && $this->__get($option) !== null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __get($option)
+ {
+ if (isset($this->options[$option]) || array_key_exists($option, $this->options)) {
+ return $this->options[$option];
+ }
+
+ if (isset($this->input[$option]) || array_key_exists($option, $this->input)) {
+ $value = $this->input[$option];
+ unset($this->input[$option]);
+
+ if (is_object($value) && method_exists($value, '__invoke')) {
+ $value = $value($this, $option);
+ }
+
+ if (isset($this->handlers[$option])) {
+ $handler = $this->handlers[$option];
+ $handler = new $handler();
+ $value = $handler->filter($this, $value);
+ }
+
+ return $this->options[$option] = $value;
+ }
+
+ if (isset($this->handlers[$option])) {
+ return $this->options[$option] = $this->getDefault($option);
+ }
+
+ return;
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/OptionsInterface.php b/vendor/predis/predis/src/Configuration/OptionsInterface.php
new file mode 100644
index 0000000..e0b30a4
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/OptionsInterface.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Command\Processor\ProcessorInterface;
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Connection\FactoryInterface;
+use Predis\Profile\ProfileInterface;
+
+/**
+ * Interface defining a container for client options.
+ *
+ * @property-read callable $aggregate Custom connection aggregator.
+ * @property-read ClusterInterface $cluster Aggregate connection for clustering.
+ * @property-read FactoryInterface $connections Connection factory.
+ * @property-read bool $exceptions Toggles exceptions in client for -ERR responses.
+ * @property-read ProcessorInterface $prefix Key prefixing strategy using the given prefix.
+ * @property-read ProfileInterface $profile Server profile.
+ * @property-read ReplicationInterface $replication Aggregate connection for replication.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface OptionsInterface
+{
+ /**
+ * Returns the default value for the given option.
+ *
+ * @param string $option Name of the option.
+ *
+ * @return mixed|null
+ */
+ public function getDefault($option);
+
+ /**
+ * Checks if the given option has been set by the user upon initialization.
+ *
+ * @param string $option Name of the option.
+ *
+ * @return bool
+ */
+ public function defined($option);
+
+ /**
+ * Checks if the given option has been set and does not evaluate to NULL.
+ *
+ * @param string $option Name of the option.
+ *
+ * @return bool
+ */
+ public function __isset($option);
+
+ /**
+ * Returns the value of the given option.
+ *
+ * @param string $option Name of the option.
+ *
+ * @return mixed|null
+ */
+ public function __get($option);
+}
diff --git a/vendor/predis/predis/src/Configuration/PrefixOption.php b/vendor/predis/predis/src/Configuration/PrefixOption.php
new file mode 100644
index 0000000..5827cdc
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/PrefixOption.php
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Command\Processor\KeyPrefixProcessor;
+use Predis\Command\Processor\ProcessorInterface;
+
+/**
+ * Configures a command processor that apply the specified prefix string to a
+ * series of Redis commands considered prefixable.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PrefixOption implements OptionInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ if ($value instanceof ProcessorInterface) {
+ return $value;
+ }
+
+ return new KeyPrefixProcessor($value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ // NOOP
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/ProfileOption.php b/vendor/predis/predis/src/Configuration/ProfileOption.php
new file mode 100644
index 0000000..864936e
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/ProfileOption.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Profile\Factory;
+use Predis\Profile\ProfileInterface;
+use Predis\Profile\RedisProfile;
+
+/**
+ * Configures the server profile to be used by the client to create command
+ * instances depending on the specified version of the Redis server.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ProfileOption implements OptionInterface
+{
+ /**
+ * Sets the commands processors that need to be applied to the profile.
+ *
+ * @param OptionsInterface $options Client options.
+ * @param ProfileInterface $profile Server profile.
+ */
+ protected function setProcessors(OptionsInterface $options, ProfileInterface $profile)
+ {
+ if (isset($options->prefix) && $profile instanceof RedisProfile) {
+ // NOTE: directly using __get('prefix') is actually a workaround for
+ // HHVM 2.3.0. It's correct and respects the options interface, it's
+ // just ugly. We will remove this hack when HHVM will fix re-entrant
+ // calls to __get() once and for all.
+
+ $profile->setProcessor($options->__get('prefix'));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ if (is_string($value)) {
+ $value = Factory::get($value);
+ $this->setProcessors($options, $value);
+ } elseif (!$value instanceof ProfileInterface) {
+ throw new \InvalidArgumentException('Invalid value for the profile option.');
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ $profile = Factory::getDefault();
+ $this->setProcessors($options, $profile);
+
+ return $profile;
+ }
+}
diff --git a/vendor/predis/predis/src/Configuration/ReplicationOption.php b/vendor/predis/predis/src/Configuration/ReplicationOption.php
new file mode 100644
index 0000000..808bcc4
--- /dev/null
+++ b/vendor/predis/predis/src/Configuration/ReplicationOption.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Configuration;
+
+use Predis\Connection\Aggregate\MasterSlaveReplication;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Connection\Aggregate\SentinelReplication;
+
+/**
+ * Configures an aggregate connection used for master/slave replication among
+ * multiple Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ReplicationOption implements OptionInterface
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @todo There's more code than needed due to a bug in filter_var() as
+ * discussed here https://bugs.php.net/bug.php?id=49510 and different
+ * behaviours when encountering NULL values on PHP 5.3.
+ */
+ public function filter(OptionsInterface $options, $value)
+ {
+ if ($value instanceof ReplicationInterface) {
+ return $value;
+ }
+
+ if ($value === 'sentinel') {
+ return function ($sentinels, $options) {
+ return new SentinelReplication($options->service, $sentinels, $options->connections);
+ };
+ }
+
+ if (
+ !is_object($value) &&
+ null !== $asbool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
+ ) {
+ if (true === $asbool) {
+ return $this->getDefault($options);
+ } else {
+ throw new \InvalidArgumentException(
+ "Values evaluating to FALSE are not accepted for `replication`"
+ );
+ }
+ }
+
+ throw new \InvalidArgumentException(
+ "An instance of type 'Predis\Connection\Aggregate\ReplicationInterface' was expected."
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefault(OptionsInterface $options)
+ {
+ $replication = new MasterSlaveReplication();
+
+ if ($options->autodiscovery) {
+ $replication->setConnectionFactory($options->connections);
+ $replication->setAutoDiscovery(true);
+ }
+
+ return $replication;
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/AbstractConnection.php b/vendor/predis/predis/src/Connection/AbstractConnection.php
new file mode 100644
index 0000000..fb86513
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/AbstractConnection.php
@@ -0,0 +1,226 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\CommunicationException;
+use Predis\Protocol\ProtocolException;
+
+/**
+ * Base class with the common logic used by connection classes to communicate
+ * with Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class AbstractConnection implements NodeConnectionInterface
+{
+ private $resource;
+ private $cachedId;
+
+ protected $parameters;
+ protected $initCommands = array();
+
+ /**
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ */
+ public function __construct(ParametersInterface $parameters)
+ {
+ $this->parameters = $this->assertParameters($parameters);
+ }
+
+ /**
+ * Disconnects from the server and destroys the underlying resource when
+ * PHP's garbage collector kicks in.
+ */
+ public function __destruct()
+ {
+ $this->disconnect();
+ }
+
+ /**
+ * Checks some of the parameters used to initialize the connection.
+ *
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return ParametersInterface
+ */
+ abstract protected function assertParameters(ParametersInterface $parameters);
+
+ /**
+ * Creates the underlying resource used to communicate with Redis.
+ *
+ * @return mixed
+ */
+ abstract protected function createResource();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ return isset($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if (!$this->isConnected()) {
+ $this->resource = $this->createResource();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ unset($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConnectCommand(CommandInterface $command)
+ {
+ $this->initCommands[] = $command;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $this->writeRequest($command);
+
+ return $this->readResponse($command);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ return $this->read();
+ }
+
+ /**
+ * Helper method that returns an exception message augmented with useful
+ * details from the connection parameters.
+ *
+ * @param string $message Error message.
+ *
+ * @return string
+ */
+ private function createExceptionMessage($message)
+ {
+ $parameters = $this->parameters;
+
+ if ($parameters->scheme === 'unix') {
+ return "$message [$parameters->scheme:$parameters->path]";
+ }
+
+ if (filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ return "$message [$parameters->scheme://[$parameters->host]:$parameters->port]";
+ }
+
+ return "$message [$parameters->scheme://$parameters->host:$parameters->port]";
+ }
+
+ /**
+ * Helper method to handle connection errors.
+ *
+ * @param string $message Error message.
+ * @param int $code Error code.
+ */
+ protected function onConnectionError($message, $code = null)
+ {
+ CommunicationException::handle(
+ new ConnectionException($this, static::createExceptionMessage($message), $code)
+ );
+ }
+
+ /**
+ * Helper method to handle protocol errors.
+ *
+ * @param string $message Error message.
+ */
+ protected function onProtocolError($message)
+ {
+ CommunicationException::handle(
+ new ProtocolException($this, static::createExceptionMessage($message))
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResource()
+ {
+ if (isset($this->resource)) {
+ return $this->resource;
+ }
+
+ $this->connect();
+
+ return $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * Gets an identifier for the connection.
+ *
+ * @return string
+ */
+ protected function getIdentifier()
+ {
+ if ($this->parameters->scheme === 'unix') {
+ return $this->parameters->path;
+ }
+
+ return "{$this->parameters->host}:{$this->parameters->port}";
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ if (!isset($this->cachedId)) {
+ $this->cachedId = $this->getIdentifier();
+ }
+
+ return $this->cachedId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array('parameters', 'initCommands');
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/ClusterInterface.php b/vendor/predis/predis/src/Connection/Aggregate/ClusterInterface.php
new file mode 100644
index 0000000..af0f5aa
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/ClusterInterface.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\Connection\AggregateConnectionInterface;
+
+/**
+ * Defines a cluster of Redis servers formed by aggregating multiple connection
+ * instances to single Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ClusterInterface extends AggregateConnectionInterface
+{
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php b/vendor/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php
new file mode 100644
index 0000000..238cf2c
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/MasterSlaveReplication.php
@@ -0,0 +1,509 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\ClientException;
+use Predis\Command\CommandInterface;
+use Predis\Command\RawCommand;
+use Predis\Connection\ConnectionException;
+use Predis\Connection\FactoryInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\Replication\MissingMasterException;
+use Predis\Replication\ReplicationStrategy;
+use Predis\Response\ErrorInterface as ResponseErrorInterface;
+
+/**
+ * Aggregate connection handling replication of Redis nodes configured in a
+ * single master / multiple slaves setup.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MasterSlaveReplication implements ReplicationInterface
+{
+ /**
+ * @var ReplicationStrategy
+ */
+ protected $strategy;
+
+ /**
+ * @var NodeConnectionInterface
+ */
+ protected $master;
+
+ /**
+ * @var NodeConnectionInterface[]
+ */
+ protected $slaves = array();
+
+ /**
+ * @var NodeConnectionInterface
+ */
+ protected $current;
+
+ /**
+ * @var bool
+ */
+ protected $autoDiscovery = false;
+
+ /**
+ * @var FactoryInterface
+ */
+ protected $connectionFactory;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ReplicationStrategy $strategy = null)
+ {
+ $this->strategy = $strategy ?: new ReplicationStrategy();
+ }
+
+ /**
+ * Configures the automatic discovery of the replication configuration on failure.
+ *
+ * @param bool $value Enable or disable auto discovery.
+ */
+ public function setAutoDiscovery($value)
+ {
+ if (!$this->connectionFactory) {
+ throw new ClientException('Automatic discovery requires a connection factory');
+ }
+
+ $this->autoDiscovery = (bool) $value;
+ }
+
+ /**
+ * Sets the connection factory used to create the connections by the auto
+ * discovery procedure.
+ *
+ * @param FactoryInterface $connectionFactory Connection factory instance.
+ */
+ public function setConnectionFactory(FactoryInterface $connectionFactory)
+ {
+ $this->connectionFactory = $connectionFactory;
+ }
+
+ /**
+ * Resets the connection state.
+ */
+ protected function reset()
+ {
+ $this->current = null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(NodeConnectionInterface $connection)
+ {
+ $alias = $connection->getParameters()->alias;
+
+ if ($alias === 'master') {
+ $this->master = $connection;
+ } else {
+ $this->slaves[$alias ?: "slave-$connection"] = $connection;
+ }
+
+ $this->reset();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(NodeConnectionInterface $connection)
+ {
+ if ($connection->getParameters()->alias === 'master') {
+ $this->master = null;
+ $this->reset();
+
+ return true;
+ } else {
+ if (($id = array_search($connection, $this->slaves, true)) !== false) {
+ unset($this->slaves[$id]);
+ $this->reset();
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnection(CommandInterface $command)
+ {
+ if (!$this->current) {
+ if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
+ $this->current = $slave;
+ } else {
+ $this->current = $this->getMasterOrDie();
+ }
+
+ return $this->current;
+ }
+
+ if ($this->current === $master = $this->getMasterOrDie()) {
+ return $master;
+ }
+
+ if (!$this->strategy->isReadOperation($command) || !$this->slaves) {
+ $this->current = $master;
+ }
+
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnectionById($connectionId)
+ {
+ if ($connectionId === 'master') {
+ return $this->master;
+ }
+
+ if (isset($this->slaves[$connectionId])) {
+ return $this->slaves[$connectionId];
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function switchTo($connection)
+ {
+ if (!$connection instanceof NodeConnectionInterface) {
+ $connection = $this->getConnectionById($connection);
+ }
+
+ if (!$connection) {
+ throw new \InvalidArgumentException('Invalid connection or connection not found.');
+ }
+
+ if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
+ throw new \InvalidArgumentException('Invalid connection or connection not found.');
+ }
+
+ $this->current = $connection;
+ }
+
+ /**
+ * Switches to the master server.
+ */
+ public function switchToMaster()
+ {
+ $this->switchTo('master');
+ }
+
+ /**
+ * Switches to a random slave server.
+ */
+ public function switchToSlave()
+ {
+ $connection = $this->pickSlave();
+ $this->switchTo($connection);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCurrent()
+ {
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMaster()
+ {
+ return $this->master;
+ }
+
+ /**
+ * Returns the connection associated to the master server.
+ *
+ * @return NodeConnectionInterface
+ */
+ private function getMasterOrDie()
+ {
+ if (!$connection = $this->getMaster()) {
+ throw new MissingMasterException('No master server available for replication');
+ }
+
+ return $connection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlaves()
+ {
+ return array_values($this->slaves);
+ }
+
+ /**
+ * Returns the underlying replication strategy.
+ *
+ * @return ReplicationStrategy
+ */
+ public function getReplicationStrategy()
+ {
+ return $this->strategy;
+ }
+
+ /**
+ * Returns a random slave.
+ *
+ * @return NodeConnectionInterface
+ */
+ protected function pickSlave()
+ {
+ if ($this->slaves) {
+ return $this->slaves[array_rand($this->slaves)];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ return $this->current ? $this->current->isConnected() : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if (!$this->current) {
+ if (!$this->current = $this->pickSlave()) {
+ if (!$this->current = $this->getMaster()) {
+ throw new ClientException('No available connection for replication');
+ }
+ }
+ }
+
+ $this->current->connect();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ if ($this->master) {
+ $this->master->disconnect();
+ }
+
+ foreach ($this->slaves as $connection) {
+ $connection->disconnect();
+ }
+ }
+
+ /**
+ * Handles response from INFO.
+ *
+ * @param string $response
+ *
+ * @return array
+ */
+ private function handleInfoResponse($response)
+ {
+ $info = array();
+
+ foreach (preg_split('/\r?\n/', $response) as $row) {
+ if (strpos($row, ':') === false) {
+ continue;
+ }
+
+ list($k, $v) = explode(':', $row, 2);
+ $info[$k] = $v;
+ }
+
+ return $info;
+ }
+
+ /**
+ * Fetches the replication configuration from one of the servers.
+ */
+ public function discover()
+ {
+ if (!$this->connectionFactory) {
+ throw new ClientException('Discovery requires a connection factory');
+ }
+
+ RETRY_FETCH: {
+ try {
+ if ($connection = $this->getMaster()) {
+ $this->discoverFromMaster($connection, $this->connectionFactory);
+ } elseif ($connection = $this->pickSlave()) {
+ $this->discoverFromSlave($connection, $this->connectionFactory);
+ } else {
+ throw new ClientException('No connection available for discovery');
+ }
+ } catch (ConnectionException $exception) {
+ $this->remove($connection);
+ goto RETRY_FETCH;
+ }
+ }
+ }
+
+ /**
+ * Discovers the replication configuration by contacting the master node.
+ *
+ * @param NodeConnectionInterface $connection Connection to the master node.
+ * @param FactoryInterface $connectionFactory Connection factory instance.
+ */
+ protected function discoverFromMaster(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
+ {
+ $response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
+ $replication = $this->handleInfoResponse($response);
+
+ if ($replication['role'] !== 'master') {
+ throw new ClientException("Role mismatch (expected master, got slave) [$connection]");
+ }
+
+ $this->slaves = array();
+
+ foreach ($replication as $k => $v) {
+ $parameters = null;
+
+ if (strpos($k, 'slave') === 0 && preg_match('/ip=(?P<host>.*),port=(?P<port>\d+)/', $v, $parameters)) {
+ $slaveConnection = $connectionFactory->create(array(
+ 'host' => $parameters['host'],
+ 'port' => $parameters['port'],
+ ));
+
+ $this->add($slaveConnection);
+ }
+ }
+ }
+
+ /**
+ * Discovers the replication configuration by contacting one of the slaves.
+ *
+ * @param NodeConnectionInterface $connection Connection to one of the slaves.
+ * @param FactoryInterface $connectionFactory Connection factory instance.
+ */
+ protected function discoverFromSlave(NodeConnectionInterface $connection, FactoryInterface $connectionFactory)
+ {
+ $response = $connection->executeCommand(RawCommand::create('INFO', 'REPLICATION'));
+ $replication = $this->handleInfoResponse($response);
+
+ if ($replication['role'] !== 'slave') {
+ throw new ClientException("Role mismatch (expected slave, got master) [$connection]");
+ }
+
+ $masterConnection = $connectionFactory->create(array(
+ 'host' => $replication['master_host'],
+ 'port' => $replication['master_port'],
+ 'alias' => 'master',
+ ));
+
+ $this->add($masterConnection);
+
+ $this->discoverFromMaster($masterConnection, $connectionFactory);
+ }
+
+ /**
+ * Retries the execution of a command upon slave failure.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $method Actual method.
+ *
+ * @return mixed
+ */
+ private function retryCommandOnFailure(CommandInterface $command, $method)
+ {
+ RETRY_COMMAND: {
+ try {
+ $connection = $this->getConnection($command);
+ $response = $connection->$method($command);
+
+ if ($response instanceof ResponseErrorInterface && $response->getErrorType() === 'LOADING') {
+ throw new ConnectionException($connection, "Redis is loading the dataset in memory [$connection]");
+ }
+ } catch (ConnectionException $exception) {
+ $connection = $exception->getConnection();
+ $connection->disconnect();
+
+ if ($connection === $this->master && !$this->autoDiscovery) {
+ // Throw immediately when master connection is failing, even
+ // when the command represents a read-only operation, unless
+ // automatic discovery has been enabled.
+ throw $exception;
+ } else {
+ // Otherwise remove the failing slave and attempt to execute
+ // the command again on one of the remaining slaves...
+ $this->remove($connection);
+ }
+
+ // ... that is, unless we have no more connections to use.
+ if (!$this->slaves && !$this->master) {
+ throw $exception;
+ } elseif ($this->autoDiscovery) {
+ $this->discover();
+ }
+
+ goto RETRY_COMMAND;
+ } catch (MissingMasterException $exception) {
+ if ($this->autoDiscovery) {
+ $this->discover();
+ } else {
+ throw $exception;
+ }
+
+ goto RETRY_COMMAND;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ return $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ return $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array('master', 'slaves', 'strategy');
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/PredisCluster.php b/vendor/predis/predis/src/Connection/Aggregate/PredisCluster.php
new file mode 100644
index 0000000..109d90b
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/PredisCluster.php
@@ -0,0 +1,237 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\Cluster\PredisStrategy;
+use Predis\Cluster\StrategyInterface;
+use Predis\Command\CommandInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Abstraction for a cluster of aggregate connections to various Redis servers
+ * implementing client-side sharding based on pluggable distribution strategies.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * @todo Add the ability to remove connections from pool.
+ */
+class PredisCluster implements ClusterInterface, \IteratorAggregate, \Countable
+{
+ private $pool;
+ private $strategy;
+ private $distributor;
+
+ /**
+ * @param StrategyInterface $strategy Optional cluster strategy.
+ */
+ public function __construct(StrategyInterface $strategy = null)
+ {
+ $this->pool = array();
+ $this->strategy = $strategy ?: new PredisStrategy();
+ $this->distributor = $this->strategy->getDistributor();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ foreach ($this->pool as $connection) {
+ if ($connection->isConnected()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ foreach ($this->pool as $connection) {
+ $connection->connect();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ foreach ($this->pool as $connection) {
+ $connection->disconnect();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(NodeConnectionInterface $connection)
+ {
+ $parameters = $connection->getParameters();
+
+ if (isset($parameters->alias)) {
+ $this->pool[$parameters->alias] = $connection;
+ } else {
+ $this->pool[] = $connection;
+ }
+
+ $weight = isset($parameters->weight) ? $parameters->weight : null;
+ $this->distributor->add($connection, $weight);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(NodeConnectionInterface $connection)
+ {
+ if (($id = array_search($connection, $this->pool, true)) !== false) {
+ unset($this->pool[$id]);
+ $this->distributor->remove($connection);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes a connection instance using its alias or index.
+ *
+ * @param string $connectionID Alias or index of a connection.
+ *
+ * @return bool Returns true if the connection was in the pool.
+ */
+ public function removeById($connectionID)
+ {
+ if ($connection = $this->getConnectionById($connectionID)) {
+ return $this->remove($connection);
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnection(CommandInterface $command)
+ {
+ $slot = $this->strategy->getSlot($command);
+
+ if (!isset($slot)) {
+ throw new NotSupportedException(
+ "Cannot use '{$command->getId()}' over clusters of connections."
+ );
+ }
+
+ $node = $this->distributor->getBySlot($slot);
+
+ return $node;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnectionById($connectionID)
+ {
+ return isset($this->pool[$connectionID]) ? $this->pool[$connectionID] : null;
+ }
+
+ /**
+ * Retrieves a connection instance from the cluster using a key.
+ *
+ * @param string $key Key string.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getConnectionByKey($key)
+ {
+ $hash = $this->strategy->getSlotByKey($key);
+ $node = $this->distributor->getBySlot($hash);
+
+ return $node;
+ }
+
+ /**
+ * Returns the underlying command hash strategy used to hash commands by
+ * using keys found in their arguments.
+ *
+ * @return StrategyInterface
+ */
+ public function getClusterStrategy()
+ {
+ return $this->strategy;
+ }
+
+ /**
+ * @return int
+ */
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return count($this->pool);
+ }
+
+ /**
+ * @return \Traversable<string|int, NodeConnectionInterface>
+ */
+ #[\ReturnTypeWillChange]
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->pool);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->getConnection($command)->writeRequest($command);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ return $this->getConnection($command)->readResponse($command);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ return $this->getConnection($command)->executeCommand($command);
+ }
+
+ /**
+ * Executes the specified Redis command on all the nodes of a cluster.
+ *
+ * @param CommandInterface $command A Redis command.
+ *
+ * @return array
+ */
+ public function executeCommandOnNodes(CommandInterface $command)
+ {
+ $responses = array();
+
+ foreach ($this->pool as $connection) {
+ $responses[] = $connection->executeCommand($command);
+ }
+
+ return $responses;
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php b/vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php
new file mode 100644
index 0000000..9e6082a
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php
@@ -0,0 +1,675 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\ClientException;
+use Predis\Cluster\RedisStrategy as RedisClusterStrategy;
+use Predis\Cluster\StrategyInterface;
+use Predis\Command\CommandInterface;
+use Predis\Command\RawCommand;
+use Predis\Connection\ConnectionException;
+use Predis\Connection\FactoryInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\NotSupportedException;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+
+/**
+ * Abstraction for a Redis-backed cluster of nodes (Redis >= 3.0.0).
+ *
+ * This connection backend offers smart support for redis-cluster by handling
+ * automatic slots map (re)generation upon -MOVED or -ASK responses returned by
+ * Redis when redirecting a client to a different node.
+ *
+ * The cluster can be pre-initialized using only a subset of the actual nodes in
+ * the cluster, Predis will do the rest by adjusting the slots map and creating
+ * the missing underlying connection instances on the fly.
+ *
+ * It is possible to pre-associate connections to a slots range with the "slots"
+ * parameter in the form "$first-$last". This can greatly reduce runtime node
+ * guessing and redirections.
+ *
+ * It is also possible to ask for the full and updated slots map directly to one
+ * of the nodes and optionally enable such a behaviour upon -MOVED redirections.
+ * Asking for the cluster configuration to Redis is actually done by issuing a
+ * CLUSTER SLOTS command to a random node in the pool.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisCluster implements ClusterInterface, \IteratorAggregate, \Countable
+{
+ private $useClusterSlots = true;
+ private $pool = array();
+ private $slots = array();
+ private $slotsMap;
+ private $strategy;
+ private $connections;
+ private $retryLimit = 5;
+
+ /**
+ * @param FactoryInterface $connections Optional connection factory.
+ * @param StrategyInterface $strategy Optional cluster strategy.
+ */
+ public function __construct(
+ FactoryInterface $connections,
+ StrategyInterface $strategy = null
+ ) {
+ $this->connections = $connections;
+ $this->strategy = $strategy ?: new RedisClusterStrategy();
+ }
+
+ /**
+ * Sets the maximum number of retries for commands upon server failure.
+ *
+ * -1 = unlimited retry attempts
+ * 0 = no retry attempts (fails immediatly)
+ * n = fail only after n retry attempts
+ *
+ * @param int $retry Number of retry attempts.
+ */
+ public function setRetryLimit($retry)
+ {
+ $this->retryLimit = (int) $retry;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ foreach ($this->pool as $connection) {
+ if ($connection->isConnected()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if ($connection = $this->getRandomConnection()) {
+ $connection->connect();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ foreach ($this->pool as $connection) {
+ $connection->disconnect();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(NodeConnectionInterface $connection)
+ {
+ $this->pool[(string) $connection] = $connection;
+ unset($this->slotsMap);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(NodeConnectionInterface $connection)
+ {
+ if (false !== $id = array_search($connection, $this->pool, true)) {
+ unset(
+ $this->pool[$id],
+ $this->slotsMap
+ );
+
+ $this->slots = array_diff($this->slots, array($connection));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Removes a connection instance by using its identifier.
+ *
+ * @param string $connectionID Connection identifier.
+ *
+ * @return bool True if the connection was in the pool.
+ */
+ public function removeById($connectionID)
+ {
+ if (isset($this->pool[$connectionID])) {
+ unset(
+ $this->pool[$connectionID],
+ $this->slotsMap
+ );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Generates the current slots map by guessing the cluster configuration out
+ * of the connection parameters of the connections in the pool.
+ *
+ * Generation is based on the same algorithm used by Redis to generate the
+ * cluster, so it is most effective when all of the connections supplied on
+ * initialization have the "slots" parameter properly set accordingly to the
+ * current cluster configuration.
+ *
+ * @return array
+ */
+ public function buildSlotsMap()
+ {
+ $this->slotsMap = array();
+
+ foreach ($this->pool as $connectionID => $connection) {
+ $parameters = $connection->getParameters();
+
+ if (!isset($parameters->slots)) {
+ continue;
+ }
+
+ foreach (explode(',', $parameters->slots) as $slotRange) {
+ $slots = explode('-', $slotRange, 2);
+
+ if (!isset($slots[1])) {
+ $slots[1] = $slots[0];
+ }
+
+ $this->setSlots($slots[0], $slots[1], $connectionID);
+ }
+ }
+
+ return $this->slotsMap;
+ }
+
+ /**
+ * Queries the specified node of the cluster to fetch the updated slots map.
+ *
+ * When the connection fails, this method tries to execute the same command
+ * on a different connection picked at random from the pool of known nodes,
+ * up until the retry limit is reached.
+ *
+ * @param NodeConnectionInterface $connection Connection to a node of the cluster.
+ *
+ * @return mixed
+ */
+ private function queryClusterNodeForSlotsMap(NodeConnectionInterface $connection)
+ {
+ $retries = 0;
+ $command = RawCommand::create('CLUSTER', 'SLOTS');
+
+ RETRY_COMMAND: {
+ try {
+ $response = $connection->executeCommand($command);
+ } catch (ConnectionException $exception) {
+ $connection = $exception->getConnection();
+ $connection->disconnect();
+
+ $this->remove($connection);
+
+ if ($retries === $this->retryLimit) {
+ throw $exception;
+ }
+
+ if (!$connection = $this->getRandomConnection()) {
+ throw new ClientException('No connections left in the pool for `CLUSTER SLOTS`');
+ }
+
+ ++$retries;
+ goto RETRY_COMMAND;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Generates an updated slots map fetching the cluster configuration using
+ * the CLUSTER SLOTS command against the specified node or a random one from
+ * the pool.
+ *
+ * @param NodeConnectionInterface $connection Optional connection instance.
+ *
+ * @return array
+ */
+ public function askSlotsMap(NodeConnectionInterface $connection = null)
+ {
+ if (!$connection && !$connection = $this->getRandomConnection()) {
+ return array();
+ }
+
+ $this->resetSlotsMap();
+
+ $response = $this->queryClusterNodeForSlotsMap($connection);
+
+ foreach ($response as $slots) {
+ // We only support master servers for now, so we ignore subsequent
+ // elements in the $slots array identifying slaves.
+ list($start, $end, $master) = $slots;
+
+ if ($master[0] === '') {
+ $this->setSlots($start, $end, (string) $connection);
+ } else {
+ $this->setSlots($start, $end, "{$master[0]}:{$master[1]}");
+ }
+ }
+
+ return $this->slotsMap;
+ }
+
+ /**
+ * Resets the slots map cache.
+ */
+ public function resetSlotsMap()
+ {
+ $this->slotsMap = array();
+ }
+
+ /**
+ * Returns the current slots map for the cluster.
+ *
+ * The order of the returned $slot => $server dictionary is not guaranteed.
+ *
+ * @return array
+ */
+ public function getSlotsMap()
+ {
+ if (!isset($this->slotsMap)) {
+ $this->slotsMap = array();
+ }
+
+ return $this->slotsMap;
+ }
+
+ /**
+ * Pre-associates a connection to a slots range to avoid runtime guessing.
+ *
+ * @param int $first Initial slot of the range.
+ * @param int $last Last slot of the range.
+ * @param NodeConnectionInterface|string $connection ID or connection instance.
+ *
+ * @throws \OutOfBoundsException
+ */
+ public function setSlots($first, $last, $connection)
+ {
+ if ($first < 0x0000 || $first > 0x3FFF ||
+ $last < 0x0000 || $last > 0x3FFF ||
+ $last < $first
+ ) {
+ throw new \OutOfBoundsException(
+ "Invalid slot range for $connection: [$first-$last]."
+ );
+ }
+
+ $slots = array_fill($first, $last - $first + 1, (string) $connection);
+ $this->slotsMap = $this->getSlotsMap() + $slots;
+ }
+
+ /**
+ * Guesses the correct node associated to a given slot using a precalculated
+ * slots map, falling back to the same logic used by Redis to initialize a
+ * cluster (best-effort).
+ *
+ * @param int $slot Slot index.
+ *
+ * @return string Connection ID.
+ */
+ protected function guessNode($slot)
+ {
+ if (!$this->pool) {
+ throw new ClientException('No connections available in the pool');
+ }
+
+ if (!isset($this->slotsMap)) {
+ $this->buildSlotsMap();
+ }
+
+ if (isset($this->slotsMap[$slot])) {
+ return $this->slotsMap[$slot];
+ }
+
+ $count = count($this->pool);
+ $index = min((int) ($slot / (int) (16384 / $count)), $count - 1);
+ $nodes = array_keys($this->pool);
+
+ return $nodes[$index];
+ }
+
+ /**
+ * Creates a new connection instance from the given connection ID.
+ *
+ * @param string $connectionID Identifier for the connection.
+ *
+ * @return NodeConnectionInterface
+ */
+ protected function createConnection($connectionID)
+ {
+ $separator = strrpos($connectionID, ':');
+
+ return $this->connections->create(array(
+ 'host' => substr($connectionID, 0, $separator),
+ 'port' => substr($connectionID, $separator + 1),
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnection(CommandInterface $command)
+ {
+ $slot = $this->strategy->getSlot($command);
+
+ if (!isset($slot)) {
+ throw new NotSupportedException(
+ "Cannot use '{$command->getId()}' with redis-cluster."
+ );
+ }
+
+ if (isset($this->slots[$slot])) {
+ return $this->slots[$slot];
+ } else {
+ return $this->getConnectionBySlot($slot);
+ }
+ }
+
+ /**
+ * Returns the connection currently associated to a given slot.
+ *
+ * @param int $slot Slot index.
+ *
+ * @throws \OutOfBoundsException
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getConnectionBySlot($slot)
+ {
+ if ($slot < 0x0000 || $slot > 0x3FFF) {
+ throw new \OutOfBoundsException("Invalid slot [$slot].");
+ }
+
+ if (isset($this->slots[$slot])) {
+ return $this->slots[$slot];
+ }
+
+ $connectionID = $this->guessNode($slot);
+
+ if (!$connection = $this->getConnectionById($connectionID)) {
+ $connection = $this->createConnection($connectionID);
+ $this->pool[$connectionID] = $connection;
+ }
+
+ return $this->slots[$slot] = $connection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnectionById($connectionID)
+ {
+ if (isset($this->pool[$connectionID])) {
+ return $this->pool[$connectionID];
+ }
+ }
+
+ /**
+ * Returns a random connection from the pool.
+ *
+ * @return NodeConnectionInterface|null
+ */
+ protected function getRandomConnection()
+ {
+ if ($this->pool) {
+ return $this->pool[array_rand($this->pool)];
+ }
+ }
+
+ /**
+ * Permanently associates the connection instance to a new slot.
+ * The connection is added to the connections pool if not yet included.
+ *
+ * @param NodeConnectionInterface $connection Connection instance.
+ * @param int $slot Target slot index.
+ */
+ protected function move(NodeConnectionInterface $connection, $slot)
+ {
+ $this->pool[(string) $connection] = $connection;
+ $this->slots[(int) $slot] = $connection;
+ }
+
+ /**
+ * Handles -ERR responses returned by Redis.
+ *
+ * @param CommandInterface $command Command that generated the -ERR response.
+ * @param ErrorResponseInterface $error Redis error response object.
+ *
+ * @return mixed
+ */
+ protected function onErrorResponse(CommandInterface $command, ErrorResponseInterface $error)
+ {
+ $details = explode(' ', $error->getMessage(), 2);
+
+ switch ($details[0]) {
+ case 'MOVED':
+ return $this->onMovedResponse($command, $details[1]);
+
+ case 'ASK':
+ return $this->onAskResponse($command, $details[1]);
+
+ default:
+ return $error;
+ }
+ }
+
+ /**
+ * Handles -MOVED responses by executing again the command against the node
+ * indicated by the Redis response.
+ *
+ * @param CommandInterface $command Command that generated the -MOVED response.
+ * @param string $details Parameters of the -MOVED response.
+ *
+ * @return mixed
+ */
+ protected function onMovedResponse(CommandInterface $command, $details)
+ {
+ list($slot, $connectionID) = explode(' ', $details, 2);
+
+ if (!$connection = $this->getConnectionById($connectionID)) {
+ $connection = $this->createConnection($connectionID);
+ }
+
+ if ($this->useClusterSlots) {
+ $this->askSlotsMap($connection);
+ }
+
+ $this->move($connection, $slot);
+ $response = $this->executeCommand($command);
+
+ return $response;
+ }
+
+ /**
+ * Handles -ASK responses by executing again the command against the node
+ * indicated by the Redis response.
+ *
+ * @param CommandInterface $command Command that generated the -ASK response.
+ * @param string $details Parameters of the -ASK response.
+ *
+ * @return mixed
+ */
+ protected function onAskResponse(CommandInterface $command, $details)
+ {
+ list($slot, $connectionID) = explode(' ', $details, 2);
+
+ if (!$connection = $this->getConnectionById($connectionID)) {
+ $connection = $this->createConnection($connectionID);
+ }
+
+ $connection->executeCommand(RawCommand::create('ASKING'));
+ $response = $connection->executeCommand($command);
+
+ return $response;
+ }
+
+ /**
+ * Ensures that a command is executed one more time on connection failure.
+ *
+ * The connection to the node that generated the error is evicted from the
+ * pool before trying to fetch an updated slots map from another node. If
+ * the new slots map points to an unreachable server the client gives up and
+ * throws the exception as the nodes participating in the cluster may still
+ * have to agree that something changed in the configuration of the cluster.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $method Actual method.
+ *
+ * @return mixed
+ */
+ private function retryCommandOnFailure(CommandInterface $command, $method)
+ {
+ $failure = false;
+
+ RETRY_COMMAND: {
+ try {
+ $response = $this->getConnection($command)->$method($command);
+ } catch (ConnectionException $exception) {
+ $connection = $exception->getConnection();
+ $connection->disconnect();
+
+ $this->remove($connection);
+
+ if ($failure) {
+ throw $exception;
+ } elseif ($this->useClusterSlots) {
+ $this->askSlotsMap();
+ }
+
+ $failure = true;
+
+ goto RETRY_COMMAND;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ return $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $response = $this->retryCommandOnFailure($command, __FUNCTION__);
+
+ if ($response instanceof ErrorResponseInterface) {
+ return $this->onErrorResponse($command, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * @return int
+ */
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return count($this->pool);
+ }
+
+ /**
+ * @return \Traversable<int, NodeConnectionInterface>
+ */
+ #[\ReturnTypeWillChange]
+ public function getIterator()
+ {
+ if ($this->useClusterSlots) {
+ $slotsmap = $this->getSlotsMap() ?: $this->askSlotsMap();
+ } else {
+ $slotsmap = $this->getSlotsMap() ?: $this->buildSlotsMap();
+ }
+
+ $connections = array();
+
+ foreach (array_unique($slotsmap) as $node) {
+ if (!$connection = $this->getConnectionById($node)) {
+ $this->add($connection = $this->createConnection($node));
+ }
+
+ $connections[] = $connection;
+ }
+
+ return new \ArrayIterator($connections);
+ }
+
+ /**
+ * Returns the underlying command hash strategy used to hash commands by
+ * using keys found in their arguments.
+ *
+ * @return StrategyInterface
+ */
+ public function getClusterStrategy()
+ {
+ return $this->strategy;
+ }
+
+ /**
+ * Returns the underlying connection factory used to create new connection
+ * instances to Redis nodes indicated by redis-cluster.
+ *
+ * @return FactoryInterface
+ */
+ public function getConnectionFactory()
+ {
+ return $this->connections;
+ }
+
+ /**
+ * Enables automatic fetching of the current slots map from one of the nodes
+ * using the CLUSTER SLOTS command. This option is enabled by default as
+ * asking the current slots map to Redis upon -MOVED responses may reduce
+ * overhead by eliminating the trial-and-error nature of the node guessing
+ * procedure, mostly when targeting many keys that would end up in a lot of
+ * redirections.
+ *
+ * The slots map can still be manually fetched using the askSlotsMap()
+ * method whether or not this option is enabled.
+ *
+ * @param bool $value Enable or disable the use of CLUSTER SLOTS.
+ */
+ public function useClusterSlots($value)
+ {
+ $this->useClusterSlots = (bool) $value;
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php b/vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php
new file mode 100644
index 0000000..e09e826
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\Connection\AggregateConnectionInterface;
+use Predis\Connection\NodeConnectionInterface;
+
+/**
+ * Defines a group of Redis nodes in a master / slave replication setup.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ReplicationInterface extends AggregateConnectionInterface
+{
+ /**
+ * Switches the internal connection instance in use.
+ *
+ * @param string $connection Alias of a connection
+ */
+ public function switchTo($connection);
+
+ /**
+ * Returns the connection instance currently in use by the aggregate
+ * connection.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getCurrent();
+
+ /**
+ * Returns the connection instance for the master Redis node.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getMaster();
+
+ /**
+ * Returns a list of connection instances to slave nodes.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getSlaves();
+}
diff --git a/vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.php b/vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.php
new file mode 100644
index 0000000..84ef804
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.php
@@ -0,0 +1,732 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection\Aggregate;
+
+use Predis\Command\CommandInterface;
+use Predis\Command\RawCommand;
+use Predis\CommunicationException;
+use Predis\Connection\ConnectionException;
+use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\Connection\Parameters;
+use Predis\Replication\ReplicationStrategy;
+use Predis\Replication\RoleException;
+use Predis\Response\Error;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\ServerException;
+
+/**
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ * @author Ville Mattila <ville@eventio.fi>
+ */
+class SentinelReplication implements ReplicationInterface
+{
+ /**
+ * @var NodeConnectionInterface
+ */
+ protected $master;
+
+ /**
+ * @var NodeConnectionInterface[]
+ */
+ protected $slaves = array();
+
+ /**
+ * @var NodeConnectionInterface
+ */
+ protected $current;
+
+ /**
+ * @var string
+ */
+ protected $service;
+
+ /**
+ * @var ConnectionFactoryInterface
+ */
+ protected $connectionFactory;
+
+ /**
+ * @var ReplicationStrategy
+ */
+ protected $strategy;
+
+ /**
+ * @var NodeConnectionInterface[]
+ */
+ protected $sentinels = array();
+
+ /**
+ * @var NodeConnectionInterface
+ */
+ protected $sentinelConnection;
+
+ /**
+ * @var float
+ */
+ protected $sentinelTimeout = 0.100;
+
+ /**
+ * Max number of automatic retries of commands upon server failure.
+ *
+ * -1 = unlimited retry attempts
+ * 0 = no retry attempts (fails immediatly)
+ * n = fail only after n retry attempts
+ *
+ * @var int
+ */
+ protected $retryLimit = 20;
+
+ /**
+ * Time to wait in milliseconds before fetching a new configuration from one
+ * of the sentinel servers.
+ *
+ * @var int
+ */
+ protected $retryWait = 1000;
+
+ /**
+ * Flag for automatic fetching of available sentinels.
+ *
+ * @var bool
+ */
+ protected $updateSentinels = false;
+
+ /**
+ * @param string $service Name of the service for autodiscovery.
+ * @param array $sentinels Sentinel servers connection parameters.
+ * @param ConnectionFactoryInterface $connectionFactory Connection factory instance.
+ * @param ReplicationStrategy $strategy Replication strategy instance.
+ */
+ public function __construct(
+ $service,
+ array $sentinels,
+ ConnectionFactoryInterface $connectionFactory,
+ ReplicationStrategy $strategy = null
+ ) {
+ $this->sentinels = $sentinels;
+ $this->service = $service;
+ $this->connectionFactory = $connectionFactory;
+ $this->strategy = $strategy ?: new ReplicationStrategy();
+ }
+
+ /**
+ * Sets a default timeout for connections to sentinels.
+ *
+ * When "timeout" is present in the connection parameters of sentinels, its
+ * value overrides the default sentinel timeout.
+ *
+ * @param float $timeout Timeout value.
+ */
+ public function setSentinelTimeout($timeout)
+ {
+ $this->sentinelTimeout = (float) $timeout;
+ }
+
+ /**
+ * Sets the maximum number of retries for commands upon server failure.
+ *
+ * -1 = unlimited retry attempts
+ * 0 = no retry attempts (fails immediatly)
+ * n = fail only after n retry attempts
+ *
+ * @param int $retry Number of retry attempts.
+ */
+ public function setRetryLimit($retry)
+ {
+ $this->retryLimit = (int) $retry;
+ }
+
+ /**
+ * Sets the time to wait (in milliseconds) before fetching a new configuration
+ * from one of the sentinels.
+ *
+ * @param float $milliseconds Time to wait before the next attempt.
+ */
+ public function setRetryWait($milliseconds)
+ {
+ $this->retryWait = (float) $milliseconds;
+ }
+
+ /**
+ * Set automatic fetching of available sentinels.
+ *
+ * @param bool $update Enable or disable automatic updates.
+ */
+ public function setUpdateSentinels($update)
+ {
+ $this->updateSentinels = (bool) $update;
+ }
+
+ /**
+ * Resets the current connection.
+ */
+ protected function reset()
+ {
+ $this->current = null;
+ }
+
+ /**
+ * Wipes the current list of master and slaves nodes.
+ */
+ protected function wipeServerList()
+ {
+ $this->reset();
+
+ $this->master = null;
+ $this->slaves = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add(NodeConnectionInterface $connection)
+ {
+ $alias = $connection->getParameters()->alias;
+
+ if ($alias === 'master') {
+ $this->master = $connection;
+ } else {
+ $this->slaves[$alias ?: count($this->slaves)] = $connection;
+ }
+
+ $this->reset();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove(NodeConnectionInterface $connection)
+ {
+ if ($connection === $this->master) {
+ $this->master = null;
+ $this->reset();
+
+ return true;
+ }
+
+ if (false !== $id = array_search($connection, $this->slaves, true)) {
+ unset($this->slaves[$id]);
+ $this->reset();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a new connection to a sentinel server.
+ *
+ * @return NodeConnectionInterface
+ */
+ protected function createSentinelConnection($parameters)
+ {
+ if ($parameters instanceof NodeConnectionInterface) {
+ return $parameters;
+ }
+
+ if (is_string($parameters)) {
+ $parameters = Parameters::parse($parameters);
+ }
+
+ if (is_array($parameters)) {
+ // NOTE: sentinels do not accept AUTH and SELECT commands so we must
+ // explicitly set them to NULL to avoid problems when using default
+ // parameters set via client options. Actually AUTH is supported for
+ // sentinels starting with Redis 5 but we have to differentiate from
+ // sentinels passwords and nodes passwords, this will be implemented
+ // in a later release.
+ $parameters['database'] = null;
+ $parameters['username'] = null;
+ $parameters['password'] = null;
+
+ if (!isset($parameters['timeout'])) {
+ $parameters['timeout'] = $this->sentinelTimeout;
+ }
+ }
+
+ $connection = $this->connectionFactory->create($parameters);
+
+ return $connection;
+ }
+
+ /**
+ * Returns the current sentinel connection.
+ *
+ * If there is no active sentinel connection, a new connection is created.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getSentinelConnection()
+ {
+ if (!$this->sentinelConnection) {
+ if (!$this->sentinels) {
+ throw new \Predis\ClientException('No sentinel server available for autodiscovery.');
+ }
+
+ $sentinel = array_shift($this->sentinels);
+ $this->sentinelConnection = $this->createSentinelConnection($sentinel);
+ }
+
+ return $this->sentinelConnection;
+ }
+
+ /**
+ * Fetches an updated list of sentinels from a sentinel.
+ */
+ public function updateSentinels()
+ {
+ SENTINEL_QUERY: {
+ $sentinel = $this->getSentinelConnection();
+
+ try {
+ $payload = $sentinel->executeCommand(
+ RawCommand::create('SENTINEL', 'sentinels', $this->service)
+ );
+
+ $this->sentinels = array();
+ // NOTE: sentinel server does not return itself, so we add it back.
+ $this->sentinels[] = $sentinel->getParameters()->toArray();
+
+ foreach ($payload as $sentinel) {
+ $this->sentinels[] = array(
+ 'host' => $sentinel[3],
+ 'port' => $sentinel[5],
+ );
+ }
+ } catch (ConnectionException $exception) {
+ $this->sentinelConnection = null;
+
+ goto SENTINEL_QUERY;
+ }
+ }
+ }
+
+ /**
+ * Fetches the details for the master and slave servers from a sentinel.
+ */
+ public function querySentinel()
+ {
+ $this->wipeServerList();
+
+ $this->updateSentinels();
+ $this->getMaster();
+ $this->getSlaves();
+ }
+
+ /**
+ * Handles error responses returned by redis-sentinel.
+ *
+ * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
+ * @param ErrorResponseInterface $error Error response.
+ */
+ private function handleSentinelErrorResponse(NodeConnectionInterface $sentinel, ErrorResponseInterface $error)
+ {
+ if ($error->getErrorType() === 'IDONTKNOW') {
+ throw new ConnectionException($sentinel, $error->getMessage());
+ } else {
+ throw new ServerException($error->getMessage());
+ }
+ }
+
+ /**
+ * Fetches the details for the master server from a sentinel.
+ *
+ * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
+ * @param string $service Name of the service.
+ *
+ * @return array
+ */
+ protected function querySentinelForMaster(NodeConnectionInterface $sentinel, $service)
+ {
+ $payload = $sentinel->executeCommand(
+ RawCommand::create('SENTINEL', 'get-master-addr-by-name', $service)
+ );
+
+ if ($payload === null) {
+ throw new ServerException('ERR No such master with that name');
+ }
+
+ if ($payload instanceof ErrorResponseInterface) {
+ $this->handleSentinelErrorResponse($sentinel, $payload);
+ }
+
+ return array(
+ 'host' => $payload[0],
+ 'port' => $payload[1],
+ 'alias' => 'master',
+ );
+ }
+
+ /**
+ * Fetches the details for the slave servers from a sentinel.
+ *
+ * @param NodeConnectionInterface $sentinel Connection to a sentinel server.
+ * @param string $service Name of the service.
+ *
+ * @return array
+ */
+ protected function querySentinelForSlaves(NodeConnectionInterface $sentinel, $service)
+ {
+ $slaves = array();
+
+ $payload = $sentinel->executeCommand(
+ RawCommand::create('SENTINEL', 'slaves', $service)
+ );
+
+ if ($payload instanceof ErrorResponseInterface) {
+ $this->handleSentinelErrorResponse($sentinel, $payload);
+ }
+
+ foreach ($payload as $slave) {
+ $flags = explode(',', $slave[9]);
+
+ if (array_intersect($flags, array('s_down', 'o_down', 'disconnected'))) {
+ continue;
+ }
+
+ $slaves[] = array(
+ 'host' => $slave[3],
+ 'port' => $slave[5],
+ 'alias' => "slave-$slave[1]",
+ );
+ }
+
+ return $slaves;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCurrent()
+ {
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMaster()
+ {
+ if ($this->master) {
+ return $this->master;
+ }
+
+ if ($this->updateSentinels) {
+ $this->updateSentinels();
+ }
+
+ SENTINEL_QUERY: {
+ $sentinel = $this->getSentinelConnection();
+
+ try {
+ $masterParameters = $this->querySentinelForMaster($sentinel, $this->service);
+ $masterConnection = $this->connectionFactory->create($masterParameters);
+
+ $this->add($masterConnection);
+ } catch (ConnectionException $exception) {
+ $this->sentinelConnection = null;
+
+ goto SENTINEL_QUERY;
+ }
+ }
+
+ return $masterConnection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSlaves()
+ {
+ if ($this->slaves) {
+ return array_values($this->slaves);
+ }
+
+ if ($this->updateSentinels) {
+ $this->updateSentinels();
+ }
+
+ SENTINEL_QUERY: {
+ $sentinel = $this->getSentinelConnection();
+
+ try {
+ $slavesParameters = $this->querySentinelForSlaves($sentinel, $this->service);
+
+ foreach ($slavesParameters as $slaveParameters) {
+ $this->add($this->connectionFactory->create($slaveParameters));
+ }
+ } catch (ConnectionException $exception) {
+ $this->sentinelConnection = null;
+
+ goto SENTINEL_QUERY;
+ }
+ }
+
+ return array_values($this->slaves ?: array());
+ }
+
+ /**
+ * Returns a random slave.
+ *
+ * @return NodeConnectionInterface
+ */
+ protected function pickSlave()
+ {
+ if ($slaves = $this->getSlaves()) {
+ return $slaves[rand(1, count($slaves)) - 1];
+ }
+ }
+
+ /**
+ * Returns the connection instance in charge for the given command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return NodeConnectionInterface
+ */
+ private function getConnectionInternal(CommandInterface $command)
+ {
+ if (!$this->current) {
+ if ($this->strategy->isReadOperation($command) && $slave = $this->pickSlave()) {
+ $this->current = $slave;
+ } else {
+ $this->current = $this->getMaster();
+ }
+
+ return $this->current;
+ }
+
+ if ($this->current === $this->master) {
+ return $this->current;
+ }
+
+ if (!$this->strategy->isReadOperation($command)) {
+ $this->current = $this->getMaster();
+ }
+
+ return $this->current;
+ }
+
+ /**
+ * Asserts that the specified connection matches an expected role.
+ *
+ * @param NodeConnectionInterface $connection Connection to a redis server.
+ * @param string $role Expected role of the server ("master", "slave" or "sentinel").
+ *
+ * @throws RoleException|ConnectionException
+ */
+ protected function assertConnectionRole(NodeConnectionInterface $connection, $role)
+ {
+ $role = strtolower($role);
+ $actualRole = $connection->executeCommand(RawCommand::create('ROLE'));
+
+ if ($actualRole instanceof Error) {
+ throw new ConnectionException($connection, $actualRole->getMessage());
+ }
+
+ if ($role !== $actualRole[0]) {
+ throw new RoleException($connection, "Expected $role but got $actualRole[0] [$connection]");
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnection(CommandInterface $command)
+ {
+ $connection = $this->getConnectionInternal($command);
+
+ if (!$connection->isConnected()) {
+ // When we do not have any available slave in the pool we can expect
+ // read-only operations to hit the master server.
+ $expectedRole = $this->strategy->isReadOperation($command) && $this->slaves ? 'slave' : 'master';
+ $this->assertConnectionRole($connection, $expectedRole);
+ }
+
+ return $connection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConnectionById($connectionId)
+ {
+ if ($connectionId === 'master') {
+ return $this->getMaster();
+ }
+
+ $this->getSlaves();
+
+ if (isset($this->slaves[$connectionId])) {
+ return $this->slaves[$connectionId];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function switchTo($connection)
+ {
+ if (!$connection instanceof NodeConnectionInterface) {
+ $connection = $this->getConnectionById($connection);
+ }
+
+ if ($connection && $connection === $this->current) {
+ return;
+ }
+
+ if ($connection !== $this->master && !in_array($connection, $this->slaves, true)) {
+ throw new \InvalidArgumentException('Invalid connection or connection not found.');
+ }
+
+ $connection->connect();
+
+ if ($this->current) {
+ $this->current->disconnect();
+ }
+
+ $this->current = $connection;
+ }
+
+ /**
+ * Switches to the master server.
+ */
+ public function switchToMaster()
+ {
+ $this->switchTo('master');
+ }
+
+ /**
+ * Switches to a random slave server.
+ */
+ public function switchToSlave()
+ {
+ $connection = $this->pickSlave();
+ $this->switchTo($connection);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ return $this->current ? $this->current->isConnected() : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if (!$this->current) {
+ if (!$this->current = $this->pickSlave()) {
+ $this->current = $this->getMaster();
+ }
+ }
+
+ $this->current->connect();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ if ($this->master) {
+ $this->master->disconnect();
+ }
+
+ foreach ($this->slaves as $connection) {
+ $connection->disconnect();
+ }
+ }
+
+ /**
+ * Retries the execution of a command upon server failure after asking a new
+ * configuration to one of the sentinels.
+ *
+ * @param CommandInterface $command Command instance.
+ * @param string $method Actual method.
+ *
+ * @return mixed
+ */
+ private function retryCommandOnFailure(CommandInterface $command, $method)
+ {
+ $retries = 0;
+
+ SENTINEL_RETRY: {
+ try {
+ $response = $this->getConnection($command)->$method($command);
+ } catch (CommunicationException $exception) {
+ $this->wipeServerList();
+ $exception->getConnection()->disconnect();
+
+ if ($retries == $this->retryLimit) {
+ throw $exception;
+ }
+
+ usleep($this->retryWait * 1000);
+
+ ++$retries;
+ goto SENTINEL_RETRY;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ return $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ return $this->retryCommandOnFailure($command, __FUNCTION__);
+ }
+
+ /**
+ * Returns the underlying replication strategy.
+ *
+ * @return ReplicationStrategy
+ */
+ public function getReplicationStrategy()
+ {
+ return $this->strategy;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array(
+ 'master', 'slaves', 'service', 'sentinels', 'connectionFactory', 'strategy',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/AggregateConnectionInterface.php b/vendor/predis/predis/src/Connection/AggregateConnectionInterface.php
new file mode 100644
index 0000000..7eeaede
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/AggregateConnectionInterface.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Defines a virtual connection composed of multiple connection instances to
+ * single Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface AggregateConnectionInterface extends ConnectionInterface
+{
+ /**
+ * Adds a connection instance to the aggregate connection.
+ *
+ * @param NodeConnectionInterface $connection Connection instance.
+ */
+ public function add(NodeConnectionInterface $connection);
+
+ /**
+ * Removes the specified connection instance from the aggregate connection.
+ *
+ * @param NodeConnectionInterface $connection Connection instance.
+ *
+ * @return bool Returns true if the connection was in the pool.
+ */
+ public function remove(NodeConnectionInterface $connection);
+
+ /**
+ * Returns the connection instance in charge for the given command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function getConnection(CommandInterface $command);
+
+ /**
+ * Returns a connection instance from the aggregate connection by its alias.
+ *
+ * @param string $connectionID Connection alias.
+ *
+ * @return NodeConnectionInterface|null
+ */
+ public function getConnectionById($connectionID);
+}
diff --git a/vendor/predis/predis/src/Connection/CompositeConnectionInterface.php b/vendor/predis/predis/src/Connection/CompositeConnectionInterface.php
new file mode 100644
index 0000000..286e082
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/CompositeConnectionInterface.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+/**
+ * Defines a connection to communicate with a single Redis server that leverages
+ * an external protocol processor to handle pluggable protocol handlers.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface CompositeConnectionInterface extends NodeConnectionInterface
+{
+ /**
+ * Returns the protocol processor used by the connection.
+ */
+ public function getProtocol();
+
+ /**
+ * Writes the buffer containing over the connection.
+ *
+ * @param string $buffer String buffer to be sent over the connection.
+ */
+ public function writeBuffer($buffer);
+
+ /**
+ * Reads the given number of bytes from the connection.
+ *
+ * @param int $length Number of bytes to read from the connection.
+ *
+ * @return string
+ */
+ public function readBuffer($length);
+
+ /**
+ * Reads a line from the connection.
+ *
+ * @param string
+ */
+ public function readLine();
+}
diff --git a/vendor/predis/predis/src/Connection/CompositeStreamConnection.php b/vendor/predis/predis/src/Connection/CompositeStreamConnection.php
new file mode 100644
index 0000000..7a35340
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/CompositeStreamConnection.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\Protocol\ProtocolProcessorInterface;
+use Predis\Protocol\Text\ProtocolProcessor as TextProtocolProcessor;
+
+/**
+ * Connection abstraction to Redis servers based on PHP's stream that uses an
+ * external protocol processor defining the protocol used for the communication.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class CompositeStreamConnection extends StreamConnection implements CompositeConnectionInterface
+{
+ protected $protocol;
+
+ /**
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ * @param ProtocolProcessorInterface $protocol Protocol processor.
+ */
+ public function __construct(
+ ParametersInterface $parameters,
+ ProtocolProcessorInterface $protocol = null
+ ) {
+ $this->parameters = $this->assertParameters($parameters);
+ $this->protocol = $protocol ?: new TextProtocolProcessor();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProtocol()
+ {
+ return $this->protocol;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeBuffer($buffer)
+ {
+ $this->write($buffer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readBuffer($length)
+ {
+ if ($length <= 0) {
+ throw new \InvalidArgumentException('Length parameter must be greater than 0.');
+ }
+
+ $value = '';
+ $socket = $this->getResource();
+
+ do {
+ $chunk = fread($socket, $length);
+
+ if ($chunk === false || $chunk === '') {
+ $this->onConnectionError('Error while reading bytes from the server.');
+ }
+
+ $value .= $chunk;
+ } while (($length -= strlen($chunk)) > 0);
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readLine()
+ {
+ $value = '';
+ $socket = $this->getResource();
+
+ do {
+ $chunk = fgets($socket);
+
+ if ($chunk === false || $chunk === '') {
+ $this->onConnectionError('Error while reading line from the server.');
+ }
+
+ $value .= $chunk;
+ } while (substr($value, -2) !== "\r\n");
+
+ return substr($value, 0, -2);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->protocol->write($this, $command);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read()
+ {
+ return $this->protocol->read($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array_merge(parent::__sleep(), array('protocol'));
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/ConnectionException.php b/vendor/predis/predis/src/Connection/ConnectionException.php
new file mode 100644
index 0000000..ef2e9d7
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/ConnectionException.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\CommunicationException;
+
+/**
+ * Exception class that identifies connection-related errors.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionException extends CommunicationException
+{
+}
diff --git a/vendor/predis/predis/src/Connection/ConnectionInterface.php b/vendor/predis/predis/src/Connection/ConnectionInterface.php
new file mode 100644
index 0000000..11ace1b
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/ConnectionInterface.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Defines a connection object used to communicate with one or multiple
+ * Redis servers.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ConnectionInterface
+{
+ /**
+ * Opens the connection to Redis.
+ */
+ public function connect();
+
+ /**
+ * Closes the connection to Redis.
+ */
+ public function disconnect();
+
+ /**
+ * Checks if the connection to Redis is considered open.
+ *
+ * @return bool
+ */
+ public function isConnected();
+
+ /**
+ * Writes the request for the given command over the connection.
+ *
+ * @param CommandInterface $command Command instance.
+ */
+ public function writeRequest(CommandInterface $command);
+
+ /**
+ * Reads the response to the given command from the connection.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return mixed
+ */
+ public function readResponse(CommandInterface $command);
+
+ /**
+ * Writes a request for the given command over the connection and reads back
+ * the response returned by Redis.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return mixed
+ */
+ public function executeCommand(CommandInterface $command);
+}
diff --git a/vendor/predis/predis/src/Connection/Factory.php b/vendor/predis/predis/src/Connection/Factory.php
new file mode 100644
index 0000000..d03e87e
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Factory.php
@@ -0,0 +1,192 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\RawCommand;
+
+/**
+ * Standard connection factory for creating connections to Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Factory implements FactoryInterface
+{
+ private $defaults = array();
+
+ protected $schemes = array(
+ 'tcp' => 'Predis\Connection\StreamConnection',
+ 'unix' => 'Predis\Connection\StreamConnection',
+ 'tls' => 'Predis\Connection\StreamConnection',
+ 'redis' => 'Predis\Connection\StreamConnection',
+ 'rediss' => 'Predis\Connection\StreamConnection',
+ 'http' => 'Predis\Connection\WebdisConnection',
+ );
+
+ /**
+ * Checks if the provided argument represents a valid connection class
+ * implementing Predis\Connection\NodeConnectionInterface. Optionally,
+ * callable objects are used for lazy initialization of connection objects.
+ *
+ * @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return mixed
+ */
+ protected function checkInitializer($initializer)
+ {
+ if (is_callable($initializer)) {
+ return $initializer;
+ }
+
+ $class = new \ReflectionClass($initializer);
+
+ if (!$class->isSubclassOf('Predis\Connection\NodeConnectionInterface')) {
+ throw new \InvalidArgumentException(
+ 'A connection initializer must be a valid connection class or a callable object.'
+ );
+ }
+
+ return $initializer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function define($scheme, $initializer)
+ {
+ $this->schemes[$scheme] = $this->checkInitializer($initializer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function undefine($scheme)
+ {
+ unset($this->schemes[$scheme]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create($parameters)
+ {
+ if (!$parameters instanceof ParametersInterface) {
+ $parameters = $this->createParameters($parameters);
+ }
+
+ $scheme = $parameters->scheme;
+
+ if (!isset($this->schemes[$scheme])) {
+ throw new \InvalidArgumentException("Unknown connection scheme: '$scheme'.");
+ }
+
+ $initializer = $this->schemes[$scheme];
+
+ if (is_callable($initializer)) {
+ $connection = call_user_func($initializer, $parameters, $this);
+ } else {
+ $connection = new $initializer($parameters);
+ $this->prepareConnection($connection);
+ }
+
+ if (!$connection instanceof NodeConnectionInterface) {
+ throw new \UnexpectedValueException(
+ 'Objects returned by connection initializers must implement '.
+ "'Predis\Connection\NodeConnectionInterface'."
+ );
+ }
+
+ return $connection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function aggregate(AggregateConnectionInterface $connection, array $parameters)
+ {
+ foreach ($parameters as $node) {
+ $connection->add($node instanceof NodeConnectionInterface ? $node : $this->create($node));
+ }
+ }
+
+ /**
+ * Assigns a default set of parameters applied to new connections.
+ *
+ * The set of parameters passed to create a new connection have precedence
+ * over the default values set for the connection factory.
+ *
+ * @param array $parameters Set of connection parameters.
+ */
+ public function setDefaultParameters(array $parameters)
+ {
+ $this->defaults = $parameters;
+ }
+
+ /**
+ * Returns the default set of parameters applied to new connections.
+ *
+ * @return array
+ */
+ public function getDefaultParameters()
+ {
+ return $this->defaults;
+ }
+
+ /**
+ * Creates a connection parameters instance from the supplied argument.
+ *
+ * @param mixed $parameters Original connection parameters.
+ *
+ * @return ParametersInterface
+ */
+ protected function createParameters($parameters)
+ {
+ if (is_string($parameters)) {
+ $parameters = Parameters::parse($parameters);
+ } else {
+ $parameters = $parameters ?: array();
+ }
+
+ if ($this->defaults) {
+ $parameters += $this->defaults;
+ }
+
+ return new Parameters($parameters);
+ }
+
+ /**
+ * Prepares a connection instance after its initialization.
+ *
+ * @param NodeConnectionInterface $connection Connection instance.
+ */
+ protected function prepareConnection(NodeConnectionInterface $connection)
+ {
+ $parameters = $connection->getParameters();
+
+ if (isset($parameters->password) && strlen($parameters->password)) {
+ $cmdAuthArgs = isset($parameters->username) && strlen($parameters->username)
+ ? array('AUTH', $parameters->username, $parameters->password)
+ : array('AUTH', $parameters->password);
+
+ $connection->addConnectCommand(
+ new RawCommand($cmdAuthArgs)
+ );
+ }
+
+ if (isset($parameters->database) && strlen($parameters->database)) {
+ $connection->addConnectCommand(
+ new RawCommand(array('SELECT', $parameters->database))
+ );
+ }
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/FactoryInterface.php b/vendor/predis/predis/src/Connection/FactoryInterface.php
new file mode 100644
index 0000000..2bae083
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/FactoryInterface.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+/**
+ * Interface for classes providing a factory of connections to Redis nodes.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface FactoryInterface
+{
+ /**
+ * Defines or overrides the connection class identified by a scheme prefix.
+ *
+ * @param string $scheme Target connection scheme.
+ * @param mixed $initializer Fully-qualified name of a class or a callable for lazy initialization.
+ */
+ public function define($scheme, $initializer);
+
+ /**
+ * Undefines the connection identified by a scheme prefix.
+ *
+ * @param string $scheme Target connection scheme.
+ */
+ public function undefine($scheme);
+
+ /**
+ * Creates a new connection object.
+ *
+ * @param mixed $parameters Initialization parameters for the connection.
+ *
+ * @return NodeConnectionInterface
+ */
+ public function create($parameters);
+
+ /**
+ * Aggregates single connections into an aggregate connection instance.
+ *
+ * @param AggregateConnectionInterface $aggregate Aggregate connection instance.
+ * @param array $parameters List of parameters for each connection.
+ */
+ public function aggregate(AggregateConnectionInterface $aggregate, array $parameters);
+}
diff --git a/vendor/predis/predis/src/Connection/NodeConnectionInterface.php b/vendor/predis/predis/src/Connection/NodeConnectionInterface.php
new file mode 100644
index 0000000..665b862
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/NodeConnectionInterface.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Defines a connection used to communicate with a single Redis node.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface NodeConnectionInterface extends ConnectionInterface
+{
+ /**
+ * Returns a string representation of the connection.
+ *
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Returns the underlying resource used to communicate with Redis.
+ *
+ * @return mixed
+ */
+ public function getResource();
+
+ /**
+ * Returns the parameters used to initialize the connection.
+ *
+ * @return ParametersInterface
+ */
+ public function getParameters();
+
+ /**
+ * Pushes the given command into a queue of commands executed when
+ * establishing the actual connection to Redis.
+ *
+ * @param CommandInterface $command Instance of a Redis command.
+ */
+ public function addConnectCommand(CommandInterface $command);
+
+ /**
+ * Reads a response from the server.
+ *
+ * @return mixed
+ */
+ public function read();
+}
diff --git a/vendor/predis/predis/src/Connection/Parameters.php b/vendor/predis/predis/src/Connection/Parameters.php
new file mode 100644
index 0000000..c1c3a73
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/Parameters.php
@@ -0,0 +1,185 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+/**
+ * Container for connection parameters used to initialize connections to Redis.
+ *
+ * {@inheritdoc}
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Parameters implements ParametersInterface
+{
+ private $parameters;
+
+ private static $defaults = array(
+ 'scheme' => 'tcp',
+ 'host' => '127.0.0.1',
+ 'port' => 6379,
+ );
+
+ /**
+ * @param array $parameters Named array of connection parameters.
+ */
+ public function __construct(array $parameters = array())
+ {
+ $this->parameters = $this->filter($parameters) + $this->getDefaults();
+ }
+
+ /**
+ * Returns some default parameters with their values.
+ *
+ * @return array
+ */
+ protected function getDefaults()
+ {
+ return self::$defaults;
+ }
+
+ /**
+ * Creates a new instance by supplying the initial parameters either in the
+ * form of an URI string or a named array.
+ *
+ * @param array|string $parameters Set of connection parameters.
+ *
+ * @return Parameters
+ */
+ public static function create($parameters)
+ {
+ if (is_string($parameters)) {
+ $parameters = static::parse($parameters);
+ }
+
+ return new static($parameters ?: array());
+ }
+
+ /**
+ * Parses an URI string returning an array of connection parameters.
+ *
+ * When using the "redis" and "rediss" schemes the URI is parsed according
+ * to the rules defined by the provisional registration documents approved
+ * by IANA. If the URI has a password in its "user-information" part or a
+ * database number in the "path" part these values override the values of
+ * "password" and "database" if they are present in the "query" part.
+ *
+ * @link http://www.iana.org/assignments/uri-schemes/prov/redis
+ * @link http://www.iana.org/assignments/uri-schemes/prov/rediss
+ *
+ * @param string $uri URI string.
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return array
+ */
+ public static function parse($uri)
+ {
+ if (stripos($uri, 'unix://') === 0) {
+ // parse_url() can parse unix:/path/to/sock so we do not need the
+ // unix:///path/to/sock hack, we will support it anyway until 2.0.
+ $uri = str_ireplace('unix://', 'unix:', $uri);
+ }
+
+ if (!$parsed = parse_url($uri)) {
+ throw new \InvalidArgumentException("Invalid parameters URI: $uri");
+ }
+
+ if (
+ isset($parsed['host'])
+ && false !== strpos($parsed['host'], '[')
+ && false !== strpos($parsed['host'], ']')
+ ) {
+ $parsed['host'] = substr($parsed['host'], 1, -1);
+ }
+
+ if (isset($parsed['query'])) {
+ parse_str($parsed['query'], $queryarray);
+ unset($parsed['query']);
+
+ $parsed = array_merge($parsed, $queryarray);
+ }
+
+ if (stripos($uri, 'redis') === 0) {
+ if (isset($parsed['user'])) {
+ if (strlen($parsed['user'])) {
+ $parsed['username'] = $parsed['user'];
+ }
+ unset($parsed['user']);
+ }
+
+ if (isset($parsed['pass'])) {
+ if (strlen($parsed['pass'])) {
+ $parsed['password'] = $parsed['pass'];
+ }
+ unset($parsed['pass']);
+ }
+
+ if (isset($parsed['path']) && preg_match('/^\/(\d+)(\/.*)?/', $parsed['path'], $path)) {
+ $parsed['database'] = $path[1];
+
+ if (isset($path[2])) {
+ $parsed['path'] = $path[2];
+ } else {
+ unset($parsed['path']);
+ }
+ }
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * Validates and converts each value of the connection parameters array.
+ *
+ * @param array $parameters Connection parameters.
+ *
+ * @return array
+ */
+ protected function filter(array $parameters)
+ {
+ return $parameters ?: array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __get($parameter)
+ {
+ if (isset($this->parameters[$parameter])) {
+ return $this->parameters[$parameter];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __isset($parameter)
+ {
+ return isset($this->parameters[$parameter]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toArray()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array('parameters');
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/ParametersInterface.php b/vendor/predis/predis/src/Connection/ParametersInterface.php
new file mode 100644
index 0000000..fd8a908
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/ParametersInterface.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+/**
+ * Interface defining a container for connection parameters.
+ *
+ * The actual list of connection parameters depends on the features supported by
+ * each connection backend class (please refer to their specific documentation),
+ * but the most common parameters used through the library are:
+ *
+ * @property-read string scheme Connection scheme, such as 'tcp' or 'unix'.
+ * @property-read string host IP address or hostname of Redis.
+ * @property-read int port TCP port on which Redis is listening to.
+ * @property-read string path Path of a UNIX domain socket file.
+ * @property-read string alias Alias for the connection.
+ * @property-read float timeout Timeout for the connect() operation.
+ * @property-read float read_write_timeout Timeout for read() and write() operations.
+ * @property-read bool async_connect Performs the connect() operation asynchronously.
+ * @property-read bool tcp_nodelay Toggles the Nagle's algorithm for coalescing.
+ * @property-read bool persistent Leaves the connection open after a GC collection.
+ * @property-read string password Password to access Redis (see the AUTH command).
+ * @property-read string database Database index (see the SELECT command).
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ParametersInterface
+{
+ /**
+ * Checks if the specified parameters is set.
+ *
+ * @param string $parameter Name of the parameter.
+ *
+ * @return bool
+ */
+ public function __isset($parameter);
+
+ /**
+ * Returns the value of the specified parameter.
+ *
+ * @param string $parameter Name of the parameter.
+ *
+ * @return mixed|null
+ */
+ public function __get($parameter);
+
+ /**
+ * Returns an array representation of the connection parameters.
+ *
+ * @return array
+ */
+ public function toArray();
+}
diff --git a/vendor/predis/predis/src/Connection/PhpiredisSocketConnection.php b/vendor/predis/predis/src/Connection/PhpiredisSocketConnection.php
new file mode 100644
index 0000000..df88172
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/PhpiredisSocketConnection.php
@@ -0,0 +1,418 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\NotSupportedException;
+use Predis\Response\Error as ErrorResponse;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * This class provides the implementation of a Predis connection that uses the
+ * PHP socket extension for network communication and wraps the phpiredis C
+ * extension (PHP bindings for hiredis) to parse the Redis protocol.
+ *
+ * This class is intended to provide an optional low-overhead alternative for
+ * processing responses from Redis compared to the standard pure-PHP classes.
+ * Differences in speed when dealing with short inline responses are practically
+ * nonexistent, the actual speed boost is for big multibulk responses when this
+ * protocol processor can parse and return responses very fast.
+ *
+ * For instructions on how to build and install the phpiredis extension, please
+ * consult the repository of the project.
+ *
+ * The connection parameters supported by this class are:
+ *
+ * - scheme: it can be either 'redis', 'tcp' or 'unix'.
+ * - host: hostname or IP address of the server.
+ * - port: TCP port of the server.
+ * - path: path of a UNIX domain socket when scheme is 'unix'.
+ * - timeout: timeout to perform the connection (default is 5 seconds).
+ * - read_write_timeout: timeout of read / write operations.
+ *
+ * @link http://github.com/nrk/phpiredis
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PhpiredisSocketConnection extends AbstractConnection
+{
+ private $reader;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ParametersInterface $parameters)
+ {
+ $this->assertExtensions();
+
+ parent::__construct($parameters);
+
+ $this->reader = $this->createReader();
+ }
+
+ /**
+ * Disconnects from the server and destroys the underlying resource and the
+ * protocol reader resource when PHP's garbage collector kicks in.
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+
+ phpiredis_reader_destroy($this->reader);
+ }
+
+ /**
+ * Checks if the socket and phpiredis extensions are loaded in PHP.
+ */
+ protected function assertExtensions()
+ {
+ if (!extension_loaded('sockets')) {
+ throw new NotSupportedException(
+ 'The "sockets" extension is required by this connection backend.'
+ );
+ }
+
+ if (!extension_loaded('phpiredis')) {
+ throw new NotSupportedException(
+ 'The "phpiredis" extension is required by this connection backend.'
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function assertParameters(ParametersInterface $parameters)
+ {
+ switch ($parameters->scheme) {
+ case 'tcp':
+ case 'redis':
+ case 'unix':
+ break;
+
+ default:
+ throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
+ }
+
+ if (isset($parameters->persistent)) {
+ throw new NotSupportedException(
+ 'Persistent connections are not supported by this connection backend.'
+ );
+ }
+
+ return $parameters;
+ }
+
+ /**
+ * Creates a new instance of the protocol reader resource.
+ *
+ * @return resource
+ */
+ private function createReader()
+ {
+ $reader = phpiredis_reader_create();
+
+ phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
+ phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());
+
+ return $reader;
+ }
+
+ /**
+ * Returns the underlying protocol reader resource.
+ *
+ * @return resource
+ */
+ protected function getReader()
+ {
+ return $this->reader;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for inline responses.
+ *
+ * @return \Closure
+ */
+ protected function getStatusHandler()
+ {
+ static $statusHandler;
+
+ if (!$statusHandler) {
+ $statusHandler = function ($payload) {
+ return StatusResponse::get($payload);
+ };
+ }
+
+ return $statusHandler;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for error responses.
+ *
+ * @return \Closure
+ */
+ protected function getErrorHandler()
+ {
+ static $errorHandler;
+
+ if (!$errorHandler) {
+ $errorHandler = function ($errorMessage) {
+ return new ErrorResponse($errorMessage);
+ };
+ }
+
+ return $errorHandler;
+ }
+
+ /**
+ * Helper method used to throw exceptions on socket errors.
+ */
+ private function emitSocketError()
+ {
+ $errno = socket_last_error();
+ $errstr = socket_strerror($errno);
+
+ $this->disconnect();
+
+ $this->onConnectionError(trim($errstr), $errno);
+ }
+
+ /**
+ * Gets the address of an host from connection parameters.
+ *
+ * @param ParametersInterface $parameters Parameters used to initialize the connection.
+ *
+ * @return string
+ */
+ protected static function getAddress(ParametersInterface $parameters)
+ {
+ if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP)) {
+ return $host;
+ }
+
+ if ($host === $address = gethostbyname($host)) {
+ return false;
+ }
+
+ return $address;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createResource()
+ {
+ $parameters = $this->parameters;
+
+ if ($parameters->scheme === 'unix') {
+ $address = $parameters->path;
+ $domain = AF_UNIX;
+ $protocol = 0;
+ } else {
+ if (false === $address = self::getAddress($parameters)) {
+ $this->onConnectionError("Cannot resolve the address of '$parameters->host'.");
+ }
+
+ $domain = filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? AF_INET6 : AF_INET;
+ $protocol = SOL_TCP;
+ }
+
+ if (false === $socket = @socket_create($domain, SOCK_STREAM, $protocol)) {
+ $this->emitSocketError();
+ }
+
+ $this->setSocketOptions($socket, $parameters);
+ $this->connectWithTimeout($socket, $address, $parameters);
+
+ return $socket;
+ }
+
+ /**
+ * Sets options on the socket resource from the connection parameters.
+ *
+ * @param resource $socket Socket resource.
+ * @param ParametersInterface $parameters Parameters used to initialize the connection.
+ */
+ private function setSocketOptions($socket, ParametersInterface $parameters)
+ {
+ if ($parameters->scheme !== 'unix') {
+ if (!socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1)) {
+ $this->emitSocketError();
+ }
+
+ if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
+ $this->emitSocketError();
+ }
+ }
+
+ if (isset($parameters->read_write_timeout)) {
+ $rwtimeout = (float) $parameters->read_write_timeout;
+ $timeoutSec = floor($rwtimeout);
+ $timeoutUsec = ($rwtimeout - $timeoutSec) * 1000000;
+
+ $timeout = array(
+ 'sec' => $timeoutSec,
+ 'usec' => $timeoutUsec,
+ );
+
+ if (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout)) {
+ $this->emitSocketError();
+ }
+
+ if (!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout)) {
+ $this->emitSocketError();
+ }
+ }
+ }
+
+ /**
+ * Opens the actual connection to the server with a timeout.
+ *
+ * @param resource $socket Socket resource.
+ * @param string $address IP address (DNS-resolved from hostname)
+ * @param ParametersInterface $parameters Parameters used to initialize the connection.
+ *
+ * @return string
+ */
+ private function connectWithTimeout($socket, $address, ParametersInterface $parameters)
+ {
+ socket_set_nonblock($socket);
+
+ if (@socket_connect($socket, $address, (int) $parameters->port) === false) {
+ $error = socket_last_error();
+
+ if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
+ $this->emitSocketError();
+ }
+ }
+
+ socket_set_block($socket);
+
+ $null = null;
+ $selectable = array($socket);
+
+ $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
+ $timeoutSecs = floor($timeout);
+ $timeoutUSecs = ($timeout - $timeoutSecs) * 1000000;
+
+ $selected = socket_select($selectable, $selectable, $null, $timeoutSecs, $timeoutUSecs);
+
+ if ($selected === 2) {
+ $this->onConnectionError('Connection refused.', SOCKET_ECONNREFUSED);
+ }
+
+ if ($selected === 0) {
+ $this->onConnectionError('Connection timed out.', SOCKET_ETIMEDOUT);
+ }
+
+ if ($selected === false) {
+ $this->emitSocketError();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if (parent::connect() && $this->initCommands) {
+ foreach ($this->initCommands as $command) {
+ $response = $this->executeCommand($command);
+
+ if ($response instanceof ErrorResponseInterface) {
+ $this->onConnectionError("`{$command->getId()}` failed: $response", 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ if ($this->isConnected()) {
+ phpiredis_reader_reset($this->reader);
+ socket_close($this->getResource());
+
+ parent::disconnect();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write($buffer)
+ {
+ $socket = $this->getResource();
+
+ while (($length = strlen($buffer)) > 0) {
+ $written = socket_write($socket, $buffer, $length);
+
+ if ($length === $written) {
+ return;
+ }
+
+ if ($written === false) {
+ $this->onConnectionError('Error while writing bytes to the server.');
+ }
+
+ $buffer = substr($buffer, $written);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read()
+ {
+ $socket = $this->getResource();
+ $reader = $this->reader;
+
+ while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
+ if (@socket_recv($socket, $buffer, 4096, 0) === false || $buffer === '' || $buffer === null) {
+ $this->emitSocketError();
+ }
+
+ phpiredis_reader_feed($reader, $buffer);
+ }
+
+ if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
+ return phpiredis_reader_get_reply($reader);
+ } else {
+ $this->onProtocolError(phpiredis_reader_get_error($reader));
+
+ return;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ array_unshift($arguments, $command->getId());
+
+ $this->write(phpiredis_format_command($arguments));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __wakeup()
+ {
+ $this->assertExtensions();
+ $this->reader = $this->createReader();
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/PhpiredisStreamConnection.php b/vendor/predis/predis/src/Connection/PhpiredisStreamConnection.php
new file mode 100644
index 0000000..51503c4
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/PhpiredisStreamConnection.php
@@ -0,0 +1,262 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\NotSupportedException;
+use Predis\Response\Error as ErrorResponse;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * This class provides the implementation of a Predis connection that uses PHP's
+ * streams for network communication and wraps the phpiredis C extension (PHP
+ * bindings for hiredis) to parse and serialize the Redis protocol.
+ *
+ * This class is intended to provide an optional low-overhead alternative for
+ * processing responses from Redis compared to the standard pure-PHP classes.
+ * Differences in speed when dealing with short inline responses are practically
+ * nonexistent, the actual speed boost is for big multibulk responses when this
+ * protocol processor can parse and return responses very fast.
+ *
+ * For instructions on how to build and install the phpiredis extension, please
+ * consult the repository of the project.
+ *
+ * The connection parameters supported by this class are:
+ *
+ * - scheme: it can be either 'redis', 'tcp' or 'unix'.
+ * - host: hostname or IP address of the server.
+ * - port: TCP port of the server.
+ * - path: path of a UNIX domain socket when scheme is 'unix'.
+ * - timeout: timeout to perform the connection.
+ * - read_write_timeout: timeout of read / write operations.
+ * - async_connect: performs the connection asynchronously.
+ * - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
+ * - persistent: the connection is left intact after a GC collection.
+ *
+ * @link https://github.com/nrk/phpiredis
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class PhpiredisStreamConnection extends StreamConnection
+{
+ private $reader;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ParametersInterface $parameters)
+ {
+ $this->assertExtensions();
+
+ parent::__construct($parameters);
+
+ $this->reader = $this->createReader();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __destruct()
+ {
+ parent::__destruct();
+
+ phpiredis_reader_destroy($this->reader);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ phpiredis_reader_reset($this->reader);
+
+ parent::disconnect();
+ }
+
+ /**
+ * Checks if the phpiredis extension is loaded in PHP.
+ */
+ private function assertExtensions()
+ {
+ if (!extension_loaded('phpiredis')) {
+ throw new NotSupportedException(
+ 'The "phpiredis" extension is required by this connection backend.'
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function assertParameters(ParametersInterface $parameters)
+ {
+ switch ($parameters->scheme) {
+ case 'tcp':
+ case 'redis':
+ case 'unix':
+ break;
+
+ case 'tls':
+ case 'rediss':
+ throw new \InvalidArgumentException('SSL encryption is not supported by this connection backend.');
+
+ default:
+ throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
+ }
+
+ return $parameters;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createStreamSocket(ParametersInterface $parameters, $address, $flags, $context = null)
+ {
+ $socket = null;
+ $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
+
+ $resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags);
+
+ if (!$resource) {
+ $this->onConnectionError(trim($errstr), $errno);
+ }
+
+ if (isset($parameters->read_write_timeout) && function_exists('socket_import_stream')) {
+ $rwtimeout = (float) $parameters->read_write_timeout;
+ $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
+
+ $timeout = array(
+ 'sec' => $timeoutSeconds = floor($rwtimeout),
+ 'usec' => ($rwtimeout - $timeoutSeconds) * 1000000,
+ );
+
+ $socket = $socket ?: socket_import_stream($resource);
+ @socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, $timeout);
+ @socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, $timeout);
+ }
+
+ if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
+ $socket = $socket ?: socket_import_stream($resource);
+ socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
+ }
+
+ return $resource;
+ }
+
+ /**
+ * Creates a new instance of the protocol reader resource.
+ *
+ * @return resource
+ */
+ private function createReader()
+ {
+ $reader = phpiredis_reader_create();
+
+ phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
+ phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());
+
+ return $reader;
+ }
+
+ /**
+ * Returns the underlying protocol reader resource.
+ *
+ * @return resource
+ */
+ protected function getReader()
+ {
+ return $this->reader;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for inline responses.
+ *
+ * @return \Closure
+ */
+ protected function getStatusHandler()
+ {
+ static $statusHandler;
+
+ if (!$statusHandler) {
+ $statusHandler = function ($payload) {
+ return StatusResponse::get($payload);
+ };
+ }
+
+ return $statusHandler;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for error responses.
+ *
+ * @return \Closure
+ */
+ protected function getErrorHandler()
+ {
+ static $errorHandler;
+
+ if (!$errorHandler) {
+ $errorHandler = function ($errorMessage) {
+ return new ErrorResponse($errorMessage);
+ };
+ }
+
+ return $errorHandler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read()
+ {
+ $socket = $this->getResource();
+ $reader = $this->reader;
+
+ while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
+ $buffer = stream_socket_recvfrom($socket, 4096);
+
+ if ($buffer === false || $buffer === '') {
+ $this->onConnectionError('Error while reading bytes from the server.');
+ }
+
+ phpiredis_reader_feed($reader, $buffer);
+ }
+
+ if ($state === PHPIREDIS_READER_STATE_COMPLETE) {
+ return phpiredis_reader_get_reply($reader);
+ } else {
+ $this->onProtocolError(phpiredis_reader_get_error($reader));
+
+ return;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ array_unshift($arguments, $command->getId());
+
+ $this->write(phpiredis_format_command($arguments));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __wakeup()
+ {
+ $this->assertExtensions();
+ $this->reader = $this->createReader();
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/StreamConnection.php b/vendor/predis/predis/src/Connection/StreamConnection.php
new file mode 100644
index 0000000..5af9a89
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/StreamConnection.php
@@ -0,0 +1,396 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\Response\Error as ErrorResponse;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * Standard connection to Redis servers implemented on top of PHP's streams.
+ * The connection parameters supported by this class are:.
+ *
+ * - scheme: it can be either 'redis', 'tcp', 'rediss', 'tls' or 'unix'.
+ * - host: hostname or IP address of the server.
+ * - port: TCP port of the server.
+ * - path: path of a UNIX domain socket when scheme is 'unix'.
+ * - timeout: timeout to perform the connection (default is 5 seconds).
+ * - read_write_timeout: timeout of read / write operations.
+ * - async_connect: performs the connection asynchronously.
+ * - tcp_nodelay: enables or disables Nagle's algorithm for coalescing.
+ * - persistent: the connection is left intact after a GC collection.
+ * - ssl: context options array (see http://php.net/manual/en/context.ssl.php)
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StreamConnection extends AbstractConnection
+{
+ /**
+ * Disconnects from the server and destroys the underlying resource when the
+ * garbage collector kicks in only if the connection has not been marked as
+ * persistent.
+ */
+ public function __destruct()
+ {
+ if (isset($this->parameters->persistent) && $this->parameters->persistent) {
+ return;
+ }
+
+ $this->disconnect();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function assertParameters(ParametersInterface $parameters)
+ {
+ switch ($parameters->scheme) {
+ case 'tcp':
+ case 'redis':
+ case 'unix':
+ break;
+
+ case 'tls':
+ case 'rediss':
+ $this->assertSslSupport($parameters);
+ break;
+
+ default:
+ throw new \InvalidArgumentException("Invalid scheme: '$parameters->scheme'.");
+ }
+
+ return $parameters;
+ }
+
+ /**
+ * Checks needed conditions for SSL-encrypted connections.
+ *
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @throws \InvalidArgumentException
+ */
+ protected function assertSslSupport(ParametersInterface $parameters)
+ {
+ if (
+ filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN) &&
+ version_compare(PHP_VERSION, '7.0.0beta') < 0
+ ) {
+ throw new \InvalidArgumentException('Persistent SSL connections require PHP >= 7.0.0.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createResource()
+ {
+ switch ($this->parameters->scheme) {
+ case 'tcp':
+ case 'redis':
+ return $this->tcpStreamInitializer($this->parameters);
+
+ case 'unix':
+ return $this->unixStreamInitializer($this->parameters);
+
+ case 'tls':
+ case 'rediss':
+ return $this->tlsStreamInitializer($this->parameters);
+
+ default:
+ throw new \InvalidArgumentException("Invalid scheme: '{$this->parameters->scheme}'.");
+ }
+ }
+
+ /**
+ * Creates a connected stream socket resource.
+ *
+ * @param ParametersInterface $parameters Connection parameters.
+ * @param string $address Address for stream_socket_client().
+ * @param int $flags Flags for stream_socket_client().
+ *
+ * @return resource
+ */
+ protected function createStreamSocket(ParametersInterface $parameters, $address, $flags)
+ {
+ $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0);
+
+ if (!$resource = @stream_socket_client($address, $errno, $errstr, $timeout, $flags)) {
+ $this->onConnectionError(trim($errstr), $errno);
+ }
+
+ if (isset($parameters->read_write_timeout)) {
+ $rwtimeout = (float) $parameters->read_write_timeout;
+ $rwtimeout = $rwtimeout > 0 ? $rwtimeout : -1;
+ $timeoutSeconds = floor($rwtimeout);
+ $timeoutUSeconds = ($rwtimeout - $timeoutSeconds) * 1000000;
+ stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
+ }
+
+ if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
+ $socket = socket_import_stream($resource);
+ socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
+ }
+
+ return $resource;
+ }
+
+ /**
+ * Initializes a TCP stream resource.
+ *
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @return resource
+ */
+ protected function tcpStreamInitializer(ParametersInterface $parameters)
+ {
+ if (!filter_var($parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $address = "tcp://$parameters->host:$parameters->port";
+ } else {
+ $address = "tcp://[$parameters->host]:$parameters->port";
+ }
+
+ $flags = STREAM_CLIENT_CONNECT;
+
+ if (isset($parameters->async_connect) && $parameters->async_connect) {
+ $flags |= STREAM_CLIENT_ASYNC_CONNECT;
+ }
+
+ if (isset($parameters->persistent)) {
+ if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
+ $flags |= STREAM_CLIENT_PERSISTENT;
+
+ if ($persistent === null) {
+ $address = "{$address}/{$parameters->persistent}";
+ }
+ }
+ }
+
+ $resource = $this->createStreamSocket($parameters, $address, $flags);
+
+ return $resource;
+ }
+
+ /**
+ * Initializes a UNIX stream resource.
+ *
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @return resource
+ */
+ protected function unixStreamInitializer(ParametersInterface $parameters)
+ {
+ if (!isset($parameters->path)) {
+ throw new \InvalidArgumentException('Missing UNIX domain socket path.');
+ }
+
+ $flags = STREAM_CLIENT_CONNECT;
+
+ if (isset($parameters->persistent)) {
+ if (false !== $persistent = filter_var($parameters->persistent, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)) {
+ $flags |= STREAM_CLIENT_PERSISTENT;
+
+ if ($persistent === null) {
+ throw new \InvalidArgumentException(
+ 'Persistent connection IDs are not supported when using UNIX domain sockets.'
+ );
+ }
+ }
+ }
+
+ $resource = $this->createStreamSocket($parameters, "unix://{$parameters->path}", $flags);
+
+ return $resource;
+ }
+
+ /**
+ * Initializes a SSL-encrypted TCP stream resource.
+ *
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @return resource
+ */
+ protected function tlsStreamInitializer(ParametersInterface $parameters)
+ {
+ $resource = $this->tcpStreamInitializer($parameters);
+ $metadata = stream_get_meta_data($resource);
+
+ // Detect if crypto mode is already enabled for this stream (PHP >= 7.0.0).
+ if (isset($metadata['crypto'])) {
+ return $resource;
+ }
+
+ if (is_array($parameters->ssl)) {
+ $options = $parameters->ssl;
+ } else {
+ $options = array();
+ }
+
+ if (!isset($options['crypto_type'])) {
+ $options['crypto_type'] = STREAM_CRYPTO_METHOD_TLS_CLIENT;
+ }
+
+ if (!stream_context_set_option($resource, array('ssl' => $options))) {
+ $this->onConnectionError('Error while setting SSL context options');
+ }
+
+ if (!stream_socket_enable_crypto($resource, true, $options['crypto_type'])) {
+ $this->onConnectionError('Error while switching to encrypted communication');
+ }
+
+ return $resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ if (parent::connect() && $this->initCommands) {
+ foreach ($this->initCommands as $command) {
+ $response = $this->executeCommand($command);
+
+ if ($response instanceof ErrorResponseInterface) {
+ $this->onConnectionError("`{$command->getId()}` failed: $response", 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ if ($this->isConnected()) {
+ fclose($this->getResource());
+ parent::disconnect();
+ }
+ }
+
+ /**
+ * Performs a write operation over the stream of the buffer containing a
+ * command serialized with the Redis wire protocol.
+ *
+ * @param string $buffer Representation of a command in the Redis wire protocol.
+ */
+ protected function write($buffer)
+ {
+ $socket = $this->getResource();
+
+ while (($length = strlen($buffer)) > 0) {
+ $written = @fwrite($socket, $buffer);
+
+ if ($length === $written) {
+ return;
+ }
+
+ if ($written === false || $written === 0) {
+ $this->onConnectionError('Error while writing bytes to the server.');
+ }
+
+ $buffer = substr($buffer, $written);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read()
+ {
+ $socket = $this->getResource();
+ $chunk = fgets($socket);
+
+ if ($chunk === false || $chunk === '') {
+ $this->onConnectionError('Error while reading line from the server.');
+ }
+
+ $prefix = $chunk[0];
+ $payload = substr($chunk, 1, -2);
+
+ switch ($prefix) {
+ case '+':
+ return StatusResponse::get($payload);
+
+ case '$':
+ $size = (int) $payload;
+
+ if ($size === -1) {
+ return;
+ }
+
+ $bulkData = '';
+ $bytesLeft = ($size += 2);
+
+ do {
+ $chunk = fread($socket, min($bytesLeft, 4096));
+
+ if ($chunk === false || $chunk === '') {
+ $this->onConnectionError('Error while reading bytes from the server.');
+ }
+
+ $bulkData .= $chunk;
+ $bytesLeft = $size - strlen($bulkData);
+ } while ($bytesLeft > 0);
+
+ return substr($bulkData, 0, -2);
+
+ case '*':
+ $count = (int) $payload;
+
+ if ($count === -1) {
+ return;
+ }
+
+ $multibulk = array();
+
+ for ($i = 0; $i < $count; ++$i) {
+ $multibulk[$i] = $this->read();
+ }
+
+ return $multibulk;
+
+ case ':':
+ $integer = (int) $payload;
+ return $integer == $payload ? $integer : $payload;
+
+ case '-':
+ return new ErrorResponse($payload);
+
+ default:
+ $this->onProtocolError("Unknown response prefix: '$prefix'.");
+
+ return;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $commandID = $command->getId();
+ $arguments = $command->getArguments();
+
+ $cmdlen = strlen($commandID);
+ $reqlen = count($arguments) + 1;
+
+ $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
+
+ foreach ($arguments as $argument) {
+ $arglen = strlen(strval($argument));
+ $buffer .= "\${$arglen}\r\n{$argument}\r\n";
+ }
+
+ $this->write($buffer);
+ }
+}
diff --git a/vendor/predis/predis/src/Connection/WebdisConnection.php b/vendor/predis/predis/src/Connection/WebdisConnection.php
new file mode 100644
index 0000000..e8cd721
--- /dev/null
+++ b/vendor/predis/predis/src/Connection/WebdisConnection.php
@@ -0,0 +1,366 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Connection;
+
+use Predis\Command\CommandInterface;
+use Predis\NotSupportedException;
+use Predis\Protocol\ProtocolException;
+use Predis\Response\Error as ErrorResponse;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * This class implements a Predis connection that actually talks with Webdis
+ * instead of connecting directly to Redis. It relies on the cURL extension to
+ * communicate with the web server and the phpiredis extension to parse the
+ * protocol for responses returned in the http response bodies.
+ *
+ * Some features are not yet available or they simply cannot be implemented:
+ * - Pipelining commands.
+ * - Publish / Subscribe.
+ * - MULTI / EXEC transactions (not yet supported by Webdis).
+ *
+ * The connection parameters supported by this class are:
+ *
+ * - scheme: must be 'http'.
+ * - host: hostname or IP address of the server.
+ * - port: TCP port of the server.
+ * - timeout: timeout to perform the connection (default is 5 seconds).
+ * - user: username for authentication.
+ * - pass: password for authentication.
+ *
+ * @link http://webd.is
+ * @link http://github.com/nicolasff/webdis
+ * @link http://github.com/seppo0010/phpiredis
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class WebdisConnection implements NodeConnectionInterface
+{
+ private $parameters;
+ private $resource;
+ private $reader;
+
+ /**
+ * @param ParametersInterface $parameters Initialization parameters for the connection.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(ParametersInterface $parameters)
+ {
+ $this->assertExtensions();
+
+ if ($parameters->scheme !== 'http') {
+ throw new \InvalidArgumentException("Invalid scheme: '{$parameters->scheme}'.");
+ }
+
+ $this->parameters = $parameters;
+
+ $this->resource = $this->createCurl();
+ $this->reader = $this->createReader();
+ }
+
+ /**
+ * Frees the underlying cURL and protocol reader resources when the garbage
+ * collector kicks in.
+ */
+ public function __destruct()
+ {
+ curl_close($this->resource);
+ phpiredis_reader_destroy($this->reader);
+ }
+
+ /**
+ * Helper method used to throw on unsupported methods.
+ *
+ * @param string $method Name of the unsupported method.
+ *
+ * @throws NotSupportedException
+ */
+ private function throwNotSupportedException($method)
+ {
+ $class = __CLASS__;
+ throw new NotSupportedException("The method $class::$method() is not supported.");
+ }
+
+ /**
+ * Checks if the cURL and phpiredis extensions are loaded in PHP.
+ */
+ private function assertExtensions()
+ {
+ if (!extension_loaded('curl')) {
+ throw new NotSupportedException(
+ 'The "curl" extension is required by this connection backend.'
+ );
+ }
+
+ if (!extension_loaded('phpiredis')) {
+ throw new NotSupportedException(
+ 'The "phpiredis" extension is required by this connection backend.'
+ );
+ }
+ }
+
+ /**
+ * Initializes cURL.
+ *
+ * @return resource
+ */
+ private function createCurl()
+ {
+ $parameters = $this->getParameters();
+ $timeout = (isset($parameters->timeout) ? (float) $parameters->timeout : 5.0) * 1000;
+
+ if (filter_var($host = $parameters->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $host = "[$host]";
+ }
+
+ $options = array(
+ CURLOPT_FAILONERROR => true,
+ CURLOPT_CONNECTTIMEOUT_MS => $timeout,
+ CURLOPT_URL => "$parameters->scheme://$host:$parameters->port",
+ CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
+ CURLOPT_POST => true,
+ CURLOPT_WRITEFUNCTION => array($this, 'feedReader'),
+ );
+
+ if (isset($parameters->user, $parameters->pass)) {
+ $options[CURLOPT_USERPWD] = "{$parameters->user}:{$parameters->pass}";
+ }
+
+ curl_setopt_array($resource = curl_init(), $options);
+
+ return $resource;
+ }
+
+ /**
+ * Initializes the phpiredis protocol reader.
+ *
+ * @return resource
+ */
+ private function createReader()
+ {
+ $reader = phpiredis_reader_create();
+
+ phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
+ phpiredis_reader_set_error_handler($reader, $this->getErrorHandler());
+
+ return $reader;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for inline responses.
+ *
+ * @return \Closure
+ */
+ protected function getStatusHandler()
+ {
+ static $statusHandler;
+
+ if (!$statusHandler) {
+ $statusHandler = function ($payload) {
+ return StatusResponse::get($payload);
+ };
+ }
+
+ return $statusHandler;
+ }
+
+ /**
+ * Returns the handler used by the protocol reader for error responses.
+ *
+ * @return \Closure
+ */
+ protected function getErrorHandler()
+ {
+ static $errorHandler;
+
+ if (!$errorHandler) {
+ $errorHandler = function ($errorMessage) {
+ return new ErrorResponse($errorMessage);
+ };
+ }
+
+ return $errorHandler;
+ }
+
+ /**
+ * Feeds the phpredis reader resource with the data read from the network.
+ *
+ * @param resource $resource Reader resource.
+ * @param string $buffer Buffer of data read from a connection.
+ *
+ * @return int
+ */
+ protected function feedReader($resource, $buffer)
+ {
+ phpiredis_reader_feed($this->reader, $buffer);
+
+ return strlen($buffer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function connect()
+ {
+ // NOOP
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disconnect()
+ {
+ // NOOP
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isConnected()
+ {
+ return true;
+ }
+
+ /**
+ * Checks if the specified command is supported by this connection class.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @throws NotSupportedException
+ *
+ * @return string
+ */
+ protected function getCommandId(CommandInterface $command)
+ {
+ switch ($commandID = $command->getId()) {
+ case 'AUTH':
+ case 'SELECT':
+ case 'MULTI':
+ case 'EXEC':
+ case 'WATCH':
+ case 'UNWATCH':
+ case 'DISCARD':
+ case 'MONITOR':
+ throw new NotSupportedException("Command '$commandID' is not allowed by Webdis.");
+
+ default:
+ return $commandID;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeRequest(CommandInterface $command)
+ {
+ $this->throwNotSupportedException(__FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readResponse(CommandInterface $command)
+ {
+ $this->throwNotSupportedException(__FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $resource = $this->resource;
+ $commandId = $this->getCommandId($command);
+
+ if ($arguments = $command->getArguments()) {
+ $arguments = implode('/', array_map('urlencode', $arguments));
+ $serializedCommand = "$commandId/$arguments.raw";
+ } else {
+ $serializedCommand = "$commandId.raw";
+ }
+
+ curl_setopt($resource, CURLOPT_POSTFIELDS, $serializedCommand);
+
+ if (curl_exec($resource) === false) {
+ $error = curl_error($resource);
+ $errno = curl_errno($resource);
+
+ throw new ConnectionException($this, trim($error), $errno);
+ }
+
+ if (phpiredis_reader_get_state($this->reader) !== PHPIREDIS_READER_STATE_COMPLETE) {
+ throw new ProtocolException($this, phpiredis_reader_get_error($this->reader));
+ }
+
+ return phpiredis_reader_get_reply($this->reader);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addConnectCommand(CommandInterface $command)
+ {
+ $this->throwNotSupportedException(__FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read()
+ {
+ $this->throwNotSupportedException(__FUNCTION__);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return "{$this->parameters->host}:{$this->parameters->port}";
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __sleep()
+ {
+ return array('parameters');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __wakeup()
+ {
+ $this->assertExtensions();
+
+ $this->resource = $this->createCurl();
+ $this->reader = $this->createReader();
+ }
+}
diff --git a/vendor/predis/predis/src/Monitor/Consumer.php b/vendor/predis/predis/src/Monitor/Consumer.php
new file mode 100644
index 0000000..6579883
--- /dev/null
+++ b/vendor/predis/predis/src/Monitor/Consumer.php
@@ -0,0 +1,178 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Monitor;
+
+use Predis\ClientInterface;
+use Predis\Connection\AggregateConnectionInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Redis MONITOR consumer.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Consumer implements \Iterator
+{
+ private $client;
+ private $valid;
+ private $position;
+
+ /**
+ * @param ClientInterface $client Client instance used by the consumer.
+ */
+ public function __construct(ClientInterface $client)
+ {
+ $this->assertClient($client);
+
+ $this->client = $client;
+
+ $this->start();
+ }
+
+ /**
+ * Automatically stops the consumer when the garbage collector kicks in.
+ */
+ public function __destruct()
+ {
+ $this->stop();
+ }
+
+ /**
+ * Checks if the passed client instance satisfies the required conditions
+ * needed to initialize a monitor consumer.
+ *
+ * @param ClientInterface $client Client instance used by the consumer.
+ *
+ * @throws NotSupportedException
+ */
+ private function assertClient(ClientInterface $client)
+ {
+ if ($client->getConnection() instanceof AggregateConnectionInterface) {
+ throw new NotSupportedException(
+ 'Cannot initialize a monitor consumer over aggregate connections.'
+ );
+ }
+
+ if ($client->getProfile()->supportsCommand('MONITOR') === false) {
+ throw new NotSupportedException("The current profile does not support 'MONITOR'.");
+ }
+ }
+
+ /**
+ * Initializes the consumer and sends the MONITOR command to the server.
+ */
+ protected function start()
+ {
+ $this->client->executeCommand(
+ $this->client->createCommand('MONITOR')
+ );
+ $this->valid = true;
+ }
+
+ /**
+ * Stops the consumer. Internally this is done by disconnecting from server
+ * since there is no way to terminate the stream initialized by MONITOR.
+ */
+ public function stop()
+ {
+ $this->client->disconnect();
+ $this->valid = false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ // NOOP
+ }
+
+ /**
+ * Returns the last message payload retrieved from the server.
+ *
+ * @return object
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ ++$this->position;
+ }
+
+ /**
+ * Checks if the the consumer is still in a valid state to continue.
+ *
+ * @return bool
+ */
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ return $this->valid;
+ }
+
+ /**
+ * Waits for a new message from the server generated by MONITOR and returns
+ * it when available.
+ *
+ * @return object
+ */
+ private function getValue()
+ {
+ $database = 0;
+ $client = null;
+ $event = $this->client->getConnection()->read();
+
+ $callback = function ($matches) use (&$database, &$client) {
+ if (2 === $count = count($matches)) {
+ // Redis <= 2.4
+ $database = (int) $matches[1];
+ }
+
+ if (4 === $count) {
+ // Redis >= 2.6
+ $database = (int) $matches[2];
+ $client = $matches[3];
+ }
+
+ return ' ';
+ };
+
+ $event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1);
+ @list($timestamp, $command, $arguments) = explode(' ', $event, 3);
+
+ return (object) array(
+ 'timestamp' => (float) $timestamp,
+ 'database' => $database,
+ 'client' => $client,
+ 'command' => substr($command, 1, -1),
+ 'arguments' => $arguments,
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/NotSupportedException.php b/vendor/predis/predis/src/NotSupportedException.php
new file mode 100644
index 0000000..be82aba
--- /dev/null
+++ b/vendor/predis/predis/src/NotSupportedException.php
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+/**
+ * Exception class thrown when trying to use features not supported by certain
+ * classes or abstractions of Predis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class NotSupportedException extends PredisException
+{
+}
diff --git a/vendor/predis/predis/src/Pipeline/Atomic.php b/vendor/predis/predis/src/Pipeline/Atomic.php
new file mode 100644
index 0000000..1c9c92a
--- /dev/null
+++ b/vendor/predis/predis/src/Pipeline/Atomic.php
@@ -0,0 +1,119 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Pipeline;
+
+use Predis\ClientException;
+use Predis\ClientInterface;
+use Predis\Connection\ConnectionInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\ResponseInterface;
+use Predis\Response\ServerException;
+
+/**
+ * Command pipeline wrapped into a MULTI / EXEC transaction.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Atomic extends Pipeline
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ClientInterface $client)
+ {
+ if (!$client->getProfile()->supportsCommands(array('multi', 'exec', 'discard'))) {
+ throw new ClientException(
+ "The current profile does not support 'MULTI', 'EXEC' and 'DISCARD'."
+ );
+ }
+
+ parent::__construct($client);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getConnection()
+ {
+ $connection = $this->getClient()->getConnection();
+
+ if (!$connection instanceof NodeConnectionInterface) {
+ $class = __CLASS__;
+
+ throw new ClientException("The class '$class' does not support aggregate connections.");
+ }
+
+ return $connection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
+ {
+ $profile = $this->getClient()->getProfile();
+ $connection->executeCommand($profile->createCommand('multi'));
+
+ foreach ($commands as $command) {
+ $connection->writeRequest($command);
+ }
+
+ foreach ($commands as $command) {
+ $response = $connection->readResponse($command);
+
+ if ($response instanceof ErrorResponseInterface) {
+ $connection->executeCommand($profile->createCommand('discard'));
+ throw new ServerException($response->getMessage());
+ }
+ }
+
+ $executed = $connection->executeCommand($profile->createCommand('exec'));
+
+ if (!isset($executed)) {
+ // TODO: should be throwing a more appropriate exception.
+ throw new ClientException(
+ 'The underlying transaction has been aborted by the server.'
+ );
+ }
+
+ if (count($executed) !== count($commands)) {
+ $expected = count($commands);
+ $received = count($executed);
+
+ throw new ClientException(
+ "Invalid number of responses [expected $expected, received $received]."
+ );
+ }
+
+ $responses = array();
+ $sizeOfPipe = count($commands);
+ $exceptions = $this->throwServerExceptions();
+
+ for ($i = 0; $i < $sizeOfPipe; ++$i) {
+ $command = $commands->dequeue();
+ $response = $executed[$i];
+
+ if (!$response instanceof ResponseInterface) {
+ $responses[] = $command->parseResponse($response);
+ } elseif ($response instanceof ErrorResponseInterface && $exceptions) {
+ $this->exception($connection, $response);
+ } else {
+ $responses[] = $response;
+ }
+
+ unset($executed[$i]);
+ }
+
+ return $responses;
+ }
+}
diff --git a/vendor/predis/predis/src/Pipeline/ConnectionErrorProof.php b/vendor/predis/predis/src/Pipeline/ConnectionErrorProof.php
new file mode 100644
index 0000000..d3bc732
--- /dev/null
+++ b/vendor/predis/predis/src/Pipeline/ConnectionErrorProof.php
@@ -0,0 +1,130 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Pipeline;
+
+use Predis\CommunicationException;
+use Predis\Connection\Aggregate\ClusterInterface;
+use Predis\Connection\ConnectionInterface;
+use Predis\Connection\NodeConnectionInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Command pipeline that does not throw exceptions on connection errors, but
+ * returns the exception instances as the rest of the response elements.
+ *
+ * @todo Awful naming!
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ConnectionErrorProof extends Pipeline
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function getConnection()
+ {
+ return $this->getClient()->getConnection();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
+ {
+ if ($connection instanceof NodeConnectionInterface) {
+ return $this->executeSingleNode($connection, $commands);
+ } elseif ($connection instanceof ClusterInterface) {
+ return $this->executeCluster($connection, $commands);
+ } else {
+ $class = get_class($connection);
+
+ throw new NotSupportedException("The connection class '$class' is not supported.");
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeSingleNode(NodeConnectionInterface $connection, \SplQueue $commands)
+ {
+ $responses = array();
+ $sizeOfPipe = count($commands);
+
+ foreach ($commands as $command) {
+ try {
+ $connection->writeRequest($command);
+ } catch (CommunicationException $exception) {
+ return array_fill(0, $sizeOfPipe, $exception);
+ }
+ }
+
+ for ($i = 0; $i < $sizeOfPipe; ++$i) {
+ $command = $commands->dequeue();
+
+ try {
+ $responses[$i] = $connection->readResponse($command);
+ } catch (CommunicationException $exception) {
+ $add = count($commands) - count($responses);
+ $responses = array_merge($responses, array_fill(0, $add, $exception));
+
+ break;
+ }
+ }
+
+ return $responses;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function executeCluster(ClusterInterface $connection, \SplQueue $commands)
+ {
+ $responses = array();
+ $sizeOfPipe = count($commands);
+ $exceptions = array();
+
+ foreach ($commands as $command) {
+ $cmdConnection = $connection->getConnection($command);
+
+ if (isset($exceptions[spl_object_hash($cmdConnection)])) {
+ continue;
+ }
+
+ try {
+ $cmdConnection->writeRequest($command);
+ } catch (CommunicationException $exception) {
+ $exceptions[spl_object_hash($cmdConnection)] = $exception;
+ }
+ }
+
+ for ($i = 0; $i < $sizeOfPipe; ++$i) {
+ $command = $commands->dequeue();
+
+ $cmdConnection = $connection->getConnection($command);
+ $connectionHash = spl_object_hash($cmdConnection);
+
+ if (isset($exceptions[$connectionHash])) {
+ $responses[$i] = $exceptions[$connectionHash];
+ continue;
+ }
+
+ try {
+ $responses[$i] = $cmdConnection->readResponse($command);
+ } catch (CommunicationException $exception) {
+ $responses[$i] = $exception;
+ $exceptions[$connectionHash] = $exception;
+ }
+ }
+
+ return $responses;
+ }
+}
diff --git a/vendor/predis/predis/src/Pipeline/FireAndForget.php b/vendor/predis/predis/src/Pipeline/FireAndForget.php
new file mode 100644
index 0000000..95a062b
--- /dev/null
+++ b/vendor/predis/predis/src/Pipeline/FireAndForget.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Pipeline;
+
+use Predis\Connection\ConnectionInterface;
+
+/**
+ * Command pipeline that writes commands to the servers but discards responses.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class FireAndForget extends Pipeline
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
+ {
+ while (!$commands->isEmpty()) {
+ $connection->writeRequest($commands->dequeue());
+ }
+
+ $connection->disconnect();
+
+ return array();
+ }
+}
diff --git a/vendor/predis/predis/src/Pipeline/Pipeline.php b/vendor/predis/predis/src/Pipeline/Pipeline.php
new file mode 100644
index 0000000..cf9c59e
--- /dev/null
+++ b/vendor/predis/predis/src/Pipeline/Pipeline.php
@@ -0,0 +1,247 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Pipeline;
+
+use Predis\ClientContextInterface;
+use Predis\ClientException;
+use Predis\ClientInterface;
+use Predis\Command\CommandInterface;
+use Predis\Connection\Aggregate\ReplicationInterface;
+use Predis\Connection\ConnectionInterface;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\ResponseInterface;
+use Predis\Response\ServerException;
+
+/**
+ * Implementation of a command pipeline in which write and read operations of
+ * Redis commands are pipelined to alleviate the effects of network round-trips.
+ *
+ * {@inheritdoc}
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Pipeline implements ClientContextInterface
+{
+ private $client;
+ private $pipeline;
+
+ private $responses = array();
+ private $running = false;
+
+ /**
+ * @param ClientInterface $client Client instance used by the context.
+ */
+ public function __construct(ClientInterface $client)
+ {
+ $this->client = $client;
+ $this->pipeline = new \SplQueue();
+ }
+
+ /**
+ * Queues a command into the pipeline buffer.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return $this
+ */
+ public function __call($method, $arguments)
+ {
+ $command = $this->client->createCommand($method, $arguments);
+ $this->recordCommand($command);
+
+ return $this;
+ }
+
+ /**
+ * Queues a command instance into the pipeline buffer.
+ *
+ * @param CommandInterface $command Command to be queued in the buffer.
+ */
+ protected function recordCommand(CommandInterface $command)
+ {
+ $this->pipeline->enqueue($command);
+ }
+
+ /**
+ * Queues a command instance into the pipeline buffer.
+ *
+ * @param CommandInterface $command Command instance to be queued in the buffer.
+ *
+ * @return $this
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $this->recordCommand($command);
+
+ return $this;
+ }
+
+ /**
+ * Throws an exception on -ERR responses returned by Redis.
+ *
+ * @param ConnectionInterface $connection Redis connection that returned the error.
+ * @param ErrorResponseInterface $response Instance of the error response.
+ *
+ * @throws ServerException
+ */
+ protected function exception(ConnectionInterface $connection, ErrorResponseInterface $response)
+ {
+ $connection->disconnect();
+ $message = $response->getMessage();
+
+ throw new ServerException($message);
+ }
+
+ /**
+ * Returns the underlying connection to be used by the pipeline.
+ *
+ * @return ConnectionInterface
+ */
+ protected function getConnection()
+ {
+ $connection = $this->getClient()->getConnection();
+
+ if ($connection instanceof ReplicationInterface) {
+ $connection->switchTo('master');
+ }
+
+ return $connection;
+ }
+
+ /**
+ * Implements the logic to flush the queued commands and read the responses
+ * from the current connection.
+ *
+ * @param ConnectionInterface $connection Current connection instance.
+ * @param \SplQueue $commands Queued commands.
+ *
+ * @return array
+ */
+ protected function executePipeline(ConnectionInterface $connection, \SplQueue $commands)
+ {
+ foreach ($commands as $command) {
+ $connection->writeRequest($command);
+ }
+
+ $responses = array();
+ $exceptions = $this->throwServerExceptions();
+
+ while (!$commands->isEmpty()) {
+ $command = $commands->dequeue();
+ $response = $connection->readResponse($command);
+
+ if (!$response instanceof ResponseInterface) {
+ $responses[] = $command->parseResponse($response);
+ } elseif ($response instanceof ErrorResponseInterface && $exceptions) {
+ $this->exception($connection, $response);
+ } else {
+ $responses[] = $response;
+ }
+ }
+
+ return $responses;
+ }
+
+ /**
+ * Flushes the buffer holding all of the commands queued so far.
+ *
+ * @param bool $send Specifies if the commands in the buffer should be sent to Redis.
+ *
+ * @return $this
+ */
+ public function flushPipeline($send = true)
+ {
+ if ($send && !$this->pipeline->isEmpty()) {
+ $responses = $this->executePipeline($this->getConnection(), $this->pipeline);
+ $this->responses = array_merge($this->responses, $responses);
+ } else {
+ $this->pipeline = new \SplQueue();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Marks the running status of the pipeline.
+ *
+ * @param bool $bool Sets the running status of the pipeline.
+ *
+ * @throws ClientException
+ */
+ private function setRunning($bool)
+ {
+ if ($bool && $this->running) {
+ throw new ClientException('The current pipeline context is already being executed.');
+ }
+
+ $this->running = $bool;
+ }
+
+ /**
+ * Handles the actual execution of the whole pipeline.
+ *
+ * @param mixed $callable Optional callback for execution.
+ *
+ * @throws \Exception
+ * @throws \InvalidArgumentException
+ *
+ * @return array
+ */
+ public function execute($callable = null)
+ {
+ if ($callable && !is_callable($callable)) {
+ throw new \InvalidArgumentException('The argument must be a callable object.');
+ }
+
+ $exception = null;
+ $this->setRunning(true);
+
+ try {
+ if ($callable) {
+ call_user_func($callable, $this);
+ }
+
+ $this->flushPipeline();
+ } catch (\Exception $exception) {
+ // NOOP
+ }
+
+ $this->setRunning(false);
+
+ if ($exception) {
+ throw $exception;
+ }
+
+ return $this->responses;
+ }
+
+ /**
+ * Returns if the pipeline should throw exceptions on server errors.
+ *
+ * @return bool
+ */
+ protected function throwServerExceptions()
+ {
+ return (bool) $this->client->getOptions()->exceptions;
+ }
+
+ /**
+ * Returns the underlying client instance used by the pipeline object.
+ *
+ * @return ClientInterface
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+}
diff --git a/vendor/predis/predis/src/PredisException.php b/vendor/predis/predis/src/PredisException.php
new file mode 100644
index 0000000..122bde1
--- /dev/null
+++ b/vendor/predis/predis/src/PredisException.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis;
+
+/**
+ * Base exception class for Predis-related errors.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class PredisException extends \Exception
+{
+}
diff --git a/vendor/predis/predis/src/Profile/Factory.php b/vendor/predis/predis/src/Profile/Factory.php
new file mode 100644
index 0000000..d4907a2
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/Factory.php
@@ -0,0 +1,101 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+use Predis\ClientException;
+
+/**
+ * Factory class for creating profile instances from strings.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+final class Factory
+{
+ private static $profiles = array(
+ '2.0' => 'Predis\Profile\RedisVersion200',
+ '2.2' => 'Predis\Profile\RedisVersion220',
+ '2.4' => 'Predis\Profile\RedisVersion240',
+ '2.6' => 'Predis\Profile\RedisVersion260',
+ '2.8' => 'Predis\Profile\RedisVersion280',
+ '3.0' => 'Predis\Profile\RedisVersion300',
+ '3.2' => 'Predis\Profile\RedisVersion320',
+ 'dev' => 'Predis\Profile\RedisUnstable',
+ 'default' => 'Predis\Profile\RedisVersion320',
+ );
+
+ /**
+ *
+ */
+ private function __construct()
+ {
+ // NOOP
+ }
+
+ /**
+ * Returns the default server profile.
+ *
+ * @return ProfileInterface
+ */
+ public static function getDefault()
+ {
+ return self::get('default');
+ }
+
+ /**
+ * Returns the development server profile.
+ *
+ * @return ProfileInterface
+ */
+ public static function getDevelopment()
+ {
+ return self::get('dev');
+ }
+
+ /**
+ * Registers a new server profile.
+ *
+ * @param string $alias Profile version or alias.
+ * @param string $class FQN of a class implementing Predis\Profile\ProfileInterface.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function define($alias, $class)
+ {
+ $reflection = new \ReflectionClass($class);
+
+ if (!$reflection->isSubclassOf('Predis\Profile\ProfileInterface')) {
+ throw new \InvalidArgumentException("The class '$class' is not a valid profile class.");
+ }
+
+ self::$profiles[$alias] = $class;
+ }
+
+ /**
+ * Returns the specified server profile.
+ *
+ * @param string $version Profile version or alias.
+ *
+ * @throws ClientException
+ *
+ * @return ProfileInterface
+ */
+ public static function get($version)
+ {
+ if (!isset(self::$profiles[$version])) {
+ throw new ClientException("Unknown server profile: '$version'.");
+ }
+
+ $profile = self::$profiles[$version];
+
+ return new $profile();
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/ProfileInterface.php b/vendor/predis/predis/src/Profile/ProfileInterface.php
new file mode 100644
index 0000000..abe71aa
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/ProfileInterface.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * A profile defines all the features and commands supported by certain versions
+ * of Redis. Instances of Predis\Client should use a server profile matching the
+ * version of Redis being used.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ProfileInterface
+{
+ /**
+ * Returns the profile version corresponding to the Redis version.
+ *
+ * @return string
+ */
+ public function getVersion();
+
+ /**
+ * Checks if the profile supports the specified command.
+ *
+ * @param string $commandID Command ID.
+ *
+ * @return bool
+ */
+ public function supportsCommand($commandID);
+
+ /**
+ * Checks if the profile supports the specified list of commands.
+ *
+ * @param array $commandIDs List of command IDs.
+ *
+ * @return string
+ */
+ public function supportsCommands(array $commandIDs);
+
+ /**
+ * Creates a new command instance.
+ *
+ * @param string $commandID Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return CommandInterface
+ */
+ public function createCommand($commandID, array $arguments = array());
+}
diff --git a/vendor/predis/predis/src/Profile/RedisProfile.php b/vendor/predis/predis/src/Profile/RedisProfile.php
new file mode 100644
index 0000000..3ef3168
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisProfile.php
@@ -0,0 +1,146 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+use Predis\ClientException;
+use Predis\Command\Processor\ProcessorInterface;
+
+/**
+ * Base class implementing common functionalities for Redis server profiles.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class RedisProfile implements ProfileInterface
+{
+ private $commands;
+ private $processor;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->commands = $this->getSupportedCommands();
+ }
+
+ /**
+ * Returns a map of all the commands supported by the profile and their
+ * actual PHP classes.
+ *
+ * @return array
+ */
+ abstract protected function getSupportedCommands();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsCommand($commandID)
+ {
+ return isset($this->commands[strtoupper($commandID)]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsCommands(array $commandIDs)
+ {
+ foreach ($commandIDs as $commandID) {
+ if (!$this->supportsCommand($commandID)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the fully-qualified name of a class representing the specified
+ * command ID registered in the current server profile.
+ *
+ * @param string $commandID Command ID.
+ *
+ * @return string|null
+ */
+ public function getCommandClass($commandID)
+ {
+ if (isset($this->commands[$commandID = strtoupper($commandID)])) {
+ return $this->commands[$commandID];
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createCommand($commandID, array $arguments = array())
+ {
+ $commandID = strtoupper($commandID);
+
+ if (!isset($this->commands[$commandID])) {
+ throw new ClientException("Command '$commandID' is not a registered Redis command.");
+ }
+
+ $commandClass = $this->commands[$commandID];
+ $command = new $commandClass();
+ $command->setArguments($arguments);
+
+ if (isset($this->processor)) {
+ $this->processor->process($command);
+ }
+
+ return $command;
+ }
+
+ /**
+ * Defines a new command in the server profile.
+ *
+ * @param string $commandID Command ID.
+ * @param string $class Fully-qualified name of a Predis\Command\CommandInterface.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function defineCommand($commandID, $class)
+ {
+ $reflection = new \ReflectionClass($class);
+
+ if (!$reflection->isSubclassOf('Predis\Command\CommandInterface')) {
+ throw new \InvalidArgumentException("The class '$class' is not a valid command class.");
+ }
+
+ $this->commands[strtoupper($commandID)] = $class;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setProcessor(ProcessorInterface $processor = null)
+ {
+ $this->processor = $processor;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProcessor()
+ {
+ return $this->processor;
+ }
+
+ /**
+ * Returns the version of server profile as its string representation.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getVersion();
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisUnstable.php b/vendor/predis/predis/src/Profile/RedisUnstable.php
new file mode 100644
index 0000000..573cc9e
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisUnstable.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for the current unstable version of Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisUnstable extends RedisVersion320
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '3.2';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array_merge(parent::getSupportedCommands(), array(
+ // EMPTY
+ ));
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion200.php b/vendor/predis/predis/src/Profile/RedisVersion200.php
new file mode 100644
index 0000000..234d53c
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion200.php
@@ -0,0 +1,173 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 2.0.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion200 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '2.0';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfo',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion220.php b/vendor/predis/predis/src/Profile/RedisVersion220.php
new file mode 100644
index 0000000..899014e
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion220.php
@@ -0,0 +1,202 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 2.2.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion220 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '2.2';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfo',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion240.php b/vendor/predis/predis/src/Profile/RedisVersion240.php
new file mode 100644
index 0000000..0856c37
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion240.php
@@ -0,0 +1,207 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 2.4.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion240 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '2.4';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfo',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+
+ /* ---------------- Redis 2.4 ---------------- */
+
+ /* remote server control commands */
+ 'CLIENT' => 'Predis\Command\ServerClient',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion260.php b/vendor/predis/predis/src/Profile/RedisVersion260.php
new file mode 100644
index 0000000..ba5084a
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion260.php
@@ -0,0 +1,235 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 2.6.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion260 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '2.6';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+ 'DUMP' => 'Predis\Command\KeyDump',
+ 'RESTORE' => 'Predis\Command\KeyRestore',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfoV26x',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+
+ /* ---------------- Redis 2.4 ---------------- */
+
+ /* remote server control commands */
+ 'CLIENT' => 'Predis\Command\ServerClient',
+
+ /* ---------------- Redis 2.6 ---------------- */
+
+ /* commands operating on the key space */
+ 'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
+ 'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
+ 'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
+ 'MIGRATE' => 'Predis\Command\KeyMigrate',
+
+ /* commands operating on string values */
+ 'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
+ 'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
+ 'BITOP' => 'Predis\Command\StringBitOp',
+ 'BITCOUNT' => 'Predis\Command\StringBitCount',
+
+ /* commands operating on hashes */
+ 'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',
+
+ /* scripting */
+ 'EVAL' => 'Predis\Command\ServerEval',
+ 'EVALSHA' => 'Predis\Command\ServerEvalSHA',
+ 'SCRIPT' => 'Predis\Command\ServerScript',
+
+ /* remote server control commands */
+ 'TIME' => 'Predis\Command\ServerTime',
+ 'SENTINEL' => 'Predis\Command\ServerSentinel',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion280.php b/vendor/predis/predis/src/Profile/RedisVersion280.php
new file mode 100644
index 0000000..ea17e68
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion280.php
@@ -0,0 +1,267 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 2.8.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion280 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '2.8';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+ 'DUMP' => 'Predis\Command\KeyDump',
+ 'RESTORE' => 'Predis\Command\KeyRestore',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfoV26x',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+
+ /* ---------------- Redis 2.4 ---------------- */
+
+ /* remote server control commands */
+ 'CLIENT' => 'Predis\Command\ServerClient',
+
+ /* ---------------- Redis 2.6 ---------------- */
+
+ /* commands operating on the key space */
+ 'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
+ 'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
+ 'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
+ 'MIGRATE' => 'Predis\Command\KeyMigrate',
+
+ /* commands operating on string values */
+ 'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
+ 'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
+ 'BITOP' => 'Predis\Command\StringBitOp',
+ 'BITCOUNT' => 'Predis\Command\StringBitCount',
+
+ /* commands operating on hashes */
+ 'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',
+
+ /* scripting */
+ 'EVAL' => 'Predis\Command\ServerEval',
+ 'EVALSHA' => 'Predis\Command\ServerEvalSHA',
+ 'SCRIPT' => 'Predis\Command\ServerScript',
+
+ /* remote server control commands */
+ 'TIME' => 'Predis\Command\ServerTime',
+ 'SENTINEL' => 'Predis\Command\ServerSentinel',
+
+ /* ---------------- Redis 2.8 ---------------- */
+
+ /* commands operating on the key space */
+ 'SCAN' => 'Predis\Command\KeyScan',
+
+ /* commands operating on string values */
+ 'BITPOS' => 'Predis\Command\StringBitPos',
+
+ /* commands operating on sets */
+ 'SSCAN' => 'Predis\Command\SetScan',
+
+ /* commands operating on sorted sets */
+ 'ZSCAN' => 'Predis\Command\ZSetScan',
+ 'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
+ 'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
+ 'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
+ 'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',
+
+ /* commands operating on hashes */
+ 'HSCAN' => 'Predis\Command\HashScan',
+
+ /* publish - subscribe */
+ 'PUBSUB' => 'Predis\Command\PubSubPubsub',
+
+ /* commands operating on HyperLogLog */
+ 'PFADD' => 'Predis\Command\HyperLogLogAdd',
+ 'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
+ 'PFMERGE' => 'Predis\Command\HyperLogLogMerge',
+
+ /* remote server control commands */
+ 'COMMAND' => 'Predis\Command\ServerCommand',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion300.php b/vendor/predis/predis/src/Profile/RedisVersion300.php
new file mode 100644
index 0000000..8a2fac8
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion300.php
@@ -0,0 +1,270 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 3.0.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion300 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '3.0';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+ 'DUMP' => 'Predis\Command\KeyDump',
+ 'RESTORE' => 'Predis\Command\KeyRestore',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfoV26x',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+
+ /* ---------------- Redis 2.4 ---------------- */
+
+ /* remote server control commands */
+ 'CLIENT' => 'Predis\Command\ServerClient',
+
+ /* ---------------- Redis 2.6 ---------------- */
+
+ /* commands operating on the key space */
+ 'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
+ 'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
+ 'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
+ 'MIGRATE' => 'Predis\Command\KeyMigrate',
+
+ /* commands operating on string values */
+ 'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
+ 'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
+ 'BITOP' => 'Predis\Command\StringBitOp',
+ 'BITCOUNT' => 'Predis\Command\StringBitCount',
+
+ /* commands operating on hashes */
+ 'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',
+
+ /* scripting */
+ 'EVAL' => 'Predis\Command\ServerEval',
+ 'EVALSHA' => 'Predis\Command\ServerEvalSHA',
+ 'SCRIPT' => 'Predis\Command\ServerScript',
+
+ /* remote server control commands */
+ 'TIME' => 'Predis\Command\ServerTime',
+ 'SENTINEL' => 'Predis\Command\ServerSentinel',
+
+ /* ---------------- Redis 2.8 ---------------- */
+
+ /* commands operating on the key space */
+ 'SCAN' => 'Predis\Command\KeyScan',
+
+ /* commands operating on string values */
+ 'BITPOS' => 'Predis\Command\StringBitPos',
+
+ /* commands operating on sets */
+ 'SSCAN' => 'Predis\Command\SetScan',
+
+ /* commands operating on sorted sets */
+ 'ZSCAN' => 'Predis\Command\ZSetScan',
+ 'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
+ 'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
+ 'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
+ 'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',
+
+ /* commands operating on hashes */
+ 'HSCAN' => 'Predis\Command\HashScan',
+
+ /* publish - subscribe */
+ 'PUBSUB' => 'Predis\Command\PubSubPubsub',
+
+ /* commands operating on HyperLogLog */
+ 'PFADD' => 'Predis\Command\HyperLogLogAdd',
+ 'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
+ 'PFMERGE' => 'Predis\Command\HyperLogLogMerge',
+
+ /* remote server control commands */
+ 'COMMAND' => 'Predis\Command\ServerCommand',
+
+ /* ---------------- Redis 3.0 ---------------- */
+
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Profile/RedisVersion320.php b/vendor/predis/predis/src/Profile/RedisVersion320.php
new file mode 100644
index 0000000..7de7957
--- /dev/null
+++ b/vendor/predis/predis/src/Profile/RedisVersion320.php
@@ -0,0 +1,281 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Profile;
+
+/**
+ * Server profile for Redis 3.0.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RedisVersion320 extends RedisProfile
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getVersion()
+ {
+ return '3.2';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSupportedCommands()
+ {
+ return array(
+ /* ---------------- Redis 1.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'EXISTS' => 'Predis\Command\KeyExists',
+ 'DEL' => 'Predis\Command\KeyDelete',
+ 'TYPE' => 'Predis\Command\KeyType',
+ 'KEYS' => 'Predis\Command\KeyKeys',
+ 'RANDOMKEY' => 'Predis\Command\KeyRandom',
+ 'RENAME' => 'Predis\Command\KeyRename',
+ 'RENAMENX' => 'Predis\Command\KeyRenamePreserve',
+ 'EXPIRE' => 'Predis\Command\KeyExpire',
+ 'EXPIREAT' => 'Predis\Command\KeyExpireAt',
+ 'TTL' => 'Predis\Command\KeyTimeToLive',
+ 'MOVE' => 'Predis\Command\KeyMove',
+ 'SORT' => 'Predis\Command\KeySort',
+ 'DUMP' => 'Predis\Command\KeyDump',
+ 'RESTORE' => 'Predis\Command\KeyRestore',
+
+ /* commands operating on string values */
+ 'SET' => 'Predis\Command\StringSet',
+ 'SETNX' => 'Predis\Command\StringSetPreserve',
+ 'MSET' => 'Predis\Command\StringSetMultiple',
+ 'MSETNX' => 'Predis\Command\StringSetMultiplePreserve',
+ 'GET' => 'Predis\Command\StringGet',
+ 'MGET' => 'Predis\Command\StringGetMultiple',
+ 'GETSET' => 'Predis\Command\StringGetSet',
+ 'INCR' => 'Predis\Command\StringIncrement',
+ 'INCRBY' => 'Predis\Command\StringIncrementBy',
+ 'DECR' => 'Predis\Command\StringDecrement',
+ 'DECRBY' => 'Predis\Command\StringDecrementBy',
+
+ /* commands operating on lists */
+ 'RPUSH' => 'Predis\Command\ListPushTail',
+ 'LPUSH' => 'Predis\Command\ListPushHead',
+ 'LLEN' => 'Predis\Command\ListLength',
+ 'LRANGE' => 'Predis\Command\ListRange',
+ 'LTRIM' => 'Predis\Command\ListTrim',
+ 'LINDEX' => 'Predis\Command\ListIndex',
+ 'LSET' => 'Predis\Command\ListSet',
+ 'LREM' => 'Predis\Command\ListRemove',
+ 'LPOP' => 'Predis\Command\ListPopFirst',
+ 'RPOP' => 'Predis\Command\ListPopLast',
+ 'RPOPLPUSH' => 'Predis\Command\ListPopLastPushHead',
+
+ /* commands operating on sets */
+ 'SADD' => 'Predis\Command\SetAdd',
+ 'SREM' => 'Predis\Command\SetRemove',
+ 'SPOP' => 'Predis\Command\SetPop',
+ 'SMOVE' => 'Predis\Command\SetMove',
+ 'SCARD' => 'Predis\Command\SetCardinality',
+ 'SISMEMBER' => 'Predis\Command\SetIsMember',
+ 'SINTER' => 'Predis\Command\SetIntersection',
+ 'SINTERSTORE' => 'Predis\Command\SetIntersectionStore',
+ 'SUNION' => 'Predis\Command\SetUnion',
+ 'SUNIONSTORE' => 'Predis\Command\SetUnionStore',
+ 'SDIFF' => 'Predis\Command\SetDifference',
+ 'SDIFFSTORE' => 'Predis\Command\SetDifferenceStore',
+ 'SMEMBERS' => 'Predis\Command\SetMembers',
+ 'SRANDMEMBER' => 'Predis\Command\SetRandomMember',
+
+ /* commands operating on sorted sets */
+ 'ZADD' => 'Predis\Command\ZSetAdd',
+ 'ZINCRBY' => 'Predis\Command\ZSetIncrementBy',
+ 'ZREM' => 'Predis\Command\ZSetRemove',
+ 'ZRANGE' => 'Predis\Command\ZSetRange',
+ 'ZREVRANGE' => 'Predis\Command\ZSetReverseRange',
+ 'ZRANGEBYSCORE' => 'Predis\Command\ZSetRangeByScore',
+ 'ZCARD' => 'Predis\Command\ZSetCardinality',
+ 'ZSCORE' => 'Predis\Command\ZSetScore',
+ 'ZREMRANGEBYSCORE' => 'Predis\Command\ZSetRemoveRangeByScore',
+
+ /* connection related commands */
+ 'PING' => 'Predis\Command\ConnectionPing',
+ 'AUTH' => 'Predis\Command\ConnectionAuth',
+ 'SELECT' => 'Predis\Command\ConnectionSelect',
+ 'ECHO' => 'Predis\Command\ConnectionEcho',
+ 'QUIT' => 'Predis\Command\ConnectionQuit',
+
+ /* remote server control commands */
+ 'INFO' => 'Predis\Command\ServerInfoV26x',
+ 'SLAVEOF' => 'Predis\Command\ServerSlaveOf',
+ 'MONITOR' => 'Predis\Command\ServerMonitor',
+ 'DBSIZE' => 'Predis\Command\ServerDatabaseSize',
+ 'FLUSHDB' => 'Predis\Command\ServerFlushDatabase',
+ 'FLUSHALL' => 'Predis\Command\ServerFlushAll',
+ 'SAVE' => 'Predis\Command\ServerSave',
+ 'BGSAVE' => 'Predis\Command\ServerBackgroundSave',
+ 'LASTSAVE' => 'Predis\Command\ServerLastSave',
+ 'SHUTDOWN' => 'Predis\Command\ServerShutdown',
+ 'BGREWRITEAOF' => 'Predis\Command\ServerBackgroundRewriteAOF',
+
+ /* ---------------- Redis 2.0 ---------------- */
+
+ /* commands operating on string values */
+ 'SETEX' => 'Predis\Command\StringSetExpire',
+ 'APPEND' => 'Predis\Command\StringAppend',
+ 'SUBSTR' => 'Predis\Command\StringSubstr',
+
+ /* commands operating on lists */
+ 'BLPOP' => 'Predis\Command\ListPopFirstBlocking',
+ 'BRPOP' => 'Predis\Command\ListPopLastBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZUNIONSTORE' => 'Predis\Command\ZSetUnionStore',
+ 'ZINTERSTORE' => 'Predis\Command\ZSetIntersectionStore',
+ 'ZCOUNT' => 'Predis\Command\ZSetCount',
+ 'ZRANK' => 'Predis\Command\ZSetRank',
+ 'ZREVRANK' => 'Predis\Command\ZSetReverseRank',
+ 'ZREMRANGEBYRANK' => 'Predis\Command\ZSetRemoveRangeByRank',
+
+ /* commands operating on hashes */
+ 'HSET' => 'Predis\Command\HashSet',
+ 'HSETNX' => 'Predis\Command\HashSetPreserve',
+ 'HMSET' => 'Predis\Command\HashSetMultiple',
+ 'HINCRBY' => 'Predis\Command\HashIncrementBy',
+ 'HGET' => 'Predis\Command\HashGet',
+ 'HMGET' => 'Predis\Command\HashGetMultiple',
+ 'HDEL' => 'Predis\Command\HashDelete',
+ 'HEXISTS' => 'Predis\Command\HashExists',
+ 'HLEN' => 'Predis\Command\HashLength',
+ 'HKEYS' => 'Predis\Command\HashKeys',
+ 'HVALS' => 'Predis\Command\HashValues',
+ 'HGETALL' => 'Predis\Command\HashGetAll',
+
+ /* transactions */
+ 'MULTI' => 'Predis\Command\TransactionMulti',
+ 'EXEC' => 'Predis\Command\TransactionExec',
+ 'DISCARD' => 'Predis\Command\TransactionDiscard',
+
+ /* publish - subscribe */
+ 'SUBSCRIBE' => 'Predis\Command\PubSubSubscribe',
+ 'UNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribe',
+ 'PSUBSCRIBE' => 'Predis\Command\PubSubSubscribeByPattern',
+ 'PUNSUBSCRIBE' => 'Predis\Command\PubSubUnsubscribeByPattern',
+ 'PUBLISH' => 'Predis\Command\PubSubPublish',
+
+ /* remote server control commands */
+ 'CONFIG' => 'Predis\Command\ServerConfig',
+
+ /* ---------------- Redis 2.2 ---------------- */
+
+ /* commands operating on the key space */
+ 'PERSIST' => 'Predis\Command\KeyPersist',
+
+ /* commands operating on string values */
+ 'STRLEN' => 'Predis\Command\StringStrlen',
+ 'SETRANGE' => 'Predis\Command\StringSetRange',
+ 'GETRANGE' => 'Predis\Command\StringGetRange',
+ 'SETBIT' => 'Predis\Command\StringSetBit',
+ 'GETBIT' => 'Predis\Command\StringGetBit',
+
+ /* commands operating on lists */
+ 'RPUSHX' => 'Predis\Command\ListPushTailX',
+ 'LPUSHX' => 'Predis\Command\ListPushHeadX',
+ 'LINSERT' => 'Predis\Command\ListInsert',
+ 'BRPOPLPUSH' => 'Predis\Command\ListPopLastPushHeadBlocking',
+
+ /* commands operating on sorted sets */
+ 'ZREVRANGEBYSCORE' => 'Predis\Command\ZSetReverseRangeByScore',
+
+ /* transactions */
+ 'WATCH' => 'Predis\Command\TransactionWatch',
+ 'UNWATCH' => 'Predis\Command\TransactionUnwatch',
+
+ /* remote server control commands */
+ 'OBJECT' => 'Predis\Command\ServerObject',
+ 'SLOWLOG' => 'Predis\Command\ServerSlowlog',
+
+ /* ---------------- Redis 2.4 ---------------- */
+
+ /* remote server control commands */
+ 'CLIENT' => 'Predis\Command\ServerClient',
+
+ /* ---------------- Redis 2.6 ---------------- */
+
+ /* commands operating on the key space */
+ 'PTTL' => 'Predis\Command\KeyPreciseTimeToLive',
+ 'PEXPIRE' => 'Predis\Command\KeyPreciseExpire',
+ 'PEXPIREAT' => 'Predis\Command\KeyPreciseExpireAt',
+ 'MIGRATE' => 'Predis\Command\KeyMigrate',
+
+ /* commands operating on string values */
+ 'PSETEX' => 'Predis\Command\StringPreciseSetExpire',
+ 'INCRBYFLOAT' => 'Predis\Command\StringIncrementByFloat',
+ 'BITOP' => 'Predis\Command\StringBitOp',
+ 'BITCOUNT' => 'Predis\Command\StringBitCount',
+
+ /* commands operating on hashes */
+ 'HINCRBYFLOAT' => 'Predis\Command\HashIncrementByFloat',
+
+ /* scripting */
+ 'EVAL' => 'Predis\Command\ServerEval',
+ 'EVALSHA' => 'Predis\Command\ServerEvalSHA',
+ 'SCRIPT' => 'Predis\Command\ServerScript',
+
+ /* remote server control commands */
+ 'TIME' => 'Predis\Command\ServerTime',
+ 'SENTINEL' => 'Predis\Command\ServerSentinel',
+
+ /* ---------------- Redis 2.8 ---------------- */
+
+ /* commands operating on the key space */
+ 'SCAN' => 'Predis\Command\KeyScan',
+
+ /* commands operating on string values */
+ 'BITPOS' => 'Predis\Command\StringBitPos',
+
+ /* commands operating on sets */
+ 'SSCAN' => 'Predis\Command\SetScan',
+
+ /* commands operating on sorted sets */
+ 'ZSCAN' => 'Predis\Command\ZSetScan',
+ 'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount',
+ 'ZRANGEBYLEX' => 'Predis\Command\ZSetRangeByLex',
+ 'ZREMRANGEBYLEX' => 'Predis\Command\ZSetRemoveRangeByLex',
+ 'ZREVRANGEBYLEX' => 'Predis\Command\ZSetReverseRangeByLex',
+
+ /* commands operating on hashes */
+ 'HSCAN' => 'Predis\Command\HashScan',
+
+ /* publish - subscribe */
+ 'PUBSUB' => 'Predis\Command\PubSubPubsub',
+
+ /* commands operating on HyperLogLog */
+ 'PFADD' => 'Predis\Command\HyperLogLogAdd',
+ 'PFCOUNT' => 'Predis\Command\HyperLogLogCount',
+ 'PFMERGE' => 'Predis\Command\HyperLogLogMerge',
+
+ /* remote server control commands */
+ 'COMMAND' => 'Predis\Command\ServerCommand',
+
+ /* ---------------- Redis 3.2 ---------------- */
+
+ /* commands operating on hashes */
+ 'HSTRLEN' => 'Predis\Command\HashStringLength',
+ 'BITFIELD' => 'Predis\Command\StringBitField',
+
+ /* commands performing geospatial operations */
+ 'GEOADD' => 'Predis\Command\GeospatialGeoAdd',
+ 'GEOHASH' => 'Predis\Command\GeospatialGeoHash',
+ 'GEOPOS' => 'Predis\Command\GeospatialGeoPos',
+ 'GEODIST' => 'Predis\Command\GeospatialGeoDist',
+ 'GEORADIUS' => 'Predis\Command\GeospatialGeoRadius',
+ 'GEORADIUSBYMEMBER' => 'Predis\Command\GeospatialGeoRadiusByMember',
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/ProtocolException.php b/vendor/predis/predis/src/Protocol/ProtocolException.php
new file mode 100644
index 0000000..6fe5d6d
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/ProtocolException.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol;
+
+use Predis\CommunicationException;
+
+/**
+ * Exception used to indentify errors encountered while parsing the Redis wire
+ * protocol.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ProtocolException extends CommunicationException
+{
+}
diff --git a/vendor/predis/predis/src/Protocol/ProtocolProcessorInterface.php b/vendor/predis/predis/src/Protocol/ProtocolProcessorInterface.php
new file mode 100644
index 0000000..b34ea18
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/ProtocolProcessorInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol;
+
+use Predis\Command\CommandInterface;
+use Predis\Connection\CompositeConnectionInterface;
+
+/**
+ * Defines a pluggable protocol processor capable of serializing commands and
+ * deserializing responses into PHP objects directly from a connection.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ProtocolProcessorInterface
+{
+ /**
+ * Writes a request over a connection to Redis.
+ *
+ * @param CompositeConnectionInterface $connection Redis connection.
+ * @param CommandInterface $command Command instance.
+ */
+ public function write(CompositeConnectionInterface $connection, CommandInterface $command);
+
+ /**
+ * Reads a response from a connection to Redis.
+ *
+ * @param CompositeConnectionInterface $connection Redis connection.
+ *
+ * @return mixed
+ */
+ public function read(CompositeConnectionInterface $connection);
+}
diff --git a/vendor/predis/predis/src/Protocol/RequestSerializerInterface.php b/vendor/predis/predis/src/Protocol/RequestSerializerInterface.php
new file mode 100644
index 0000000..eef72a6
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/RequestSerializerInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol;
+
+use Predis\Command\CommandInterface;
+
+/**
+ * Defines a pluggable serializer for Redis commands.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface RequestSerializerInterface
+{
+ /**
+ * Serializes a Redis command.
+ *
+ * @param CommandInterface $command Redis command.
+ *
+ * @return string
+ */
+ public function serialize(CommandInterface $command);
+}
diff --git a/vendor/predis/predis/src/Protocol/ResponseReaderInterface.php b/vendor/predis/predis/src/Protocol/ResponseReaderInterface.php
new file mode 100644
index 0000000..86a7bdc
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/ResponseReaderInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol;
+
+use Predis\Connection\CompositeConnectionInterface;
+
+/**
+ * Defines a pluggable reader capable of parsing responses returned by Redis and
+ * deserializing them to PHP objects.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ResponseReaderInterface
+{
+ /**
+ * Reads a response from a connection to Redis.
+ *
+ * @param CompositeConnectionInterface $connection Redis connection.
+ *
+ * @return mixed
+ */
+ public function read(CompositeConnectionInterface $connection);
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php b/vendor/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php
new file mode 100644
index 0000000..ea85ed3
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/CompositeProtocolProcessor.php
@@ -0,0 +1,107 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text;
+
+use Predis\Command\CommandInterface;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolProcessorInterface;
+use Predis\Protocol\RequestSerializerInterface;
+use Predis\Protocol\ResponseReaderInterface;
+
+/**
+ * Composite protocol processor for the standard Redis wire protocol using
+ * pluggable handlers to serialize requests and deserialize responses.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class CompositeProtocolProcessor implements ProtocolProcessorInterface
+{
+ /*
+ * @var RequestSerializerInterface
+ */
+ protected $serializer;
+
+ /*
+ * @var ResponseReaderInterface
+ */
+ protected $reader;
+
+ /**
+ * @param RequestSerializerInterface $serializer Request serializer.
+ * @param ResponseReaderInterface $reader Response reader.
+ */
+ public function __construct(
+ RequestSerializerInterface $serializer = null,
+ ResponseReaderInterface $reader = null
+ ) {
+ $this->setRequestSerializer($serializer ?: new RequestSerializer());
+ $this->setResponseReader($reader ?: new ResponseReader());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write(CompositeConnectionInterface $connection, CommandInterface $command)
+ {
+ $connection->writeBuffer($this->serializer->serialize($command));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read(CompositeConnectionInterface $connection)
+ {
+ return $this->reader->read($connection);
+ }
+
+ /**
+ * Sets the request serializer used by the protocol processor.
+ *
+ * @param RequestSerializerInterface $serializer Request serializer.
+ */
+ public function setRequestSerializer(RequestSerializerInterface $serializer)
+ {
+ $this->serializer = $serializer;
+ }
+
+ /**
+ * Returns the request serializer used by the protocol processor.
+ *
+ * @return RequestSerializerInterface
+ */
+ public function getRequestSerializer()
+ {
+ return $this->serializer;
+ }
+
+ /**
+ * Sets the response reader used by the protocol processor.
+ *
+ * @param ResponseReaderInterface $reader Response reader.
+ */
+ public function setResponseReader(ResponseReaderInterface $reader)
+ {
+ $this->reader = $reader;
+ }
+
+ /**
+ * Returns the Response reader used by the protocol processor.
+ *
+ * @return ResponseReaderInterface
+ */
+ public function getResponseReader()
+ {
+ return $this->reader;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/BulkResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/BulkResponse.php
new file mode 100644
index 0000000..5b0bf3c
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/BulkResponse.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+
+/**
+ * Handler for the bulk response type in the standard Redis wire protocol.
+ * It translates the payload to a string or a NULL.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class BulkResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ $length = (int) $payload;
+
+ if ("$length" !== $payload) {
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Cannot parse '$payload' as a valid length for a bulk response."
+ ));
+ }
+
+ if ($length >= 0) {
+ return substr($connection->readBuffer($length + 2), 0, -2);
+ }
+
+ if ($length == -1) {
+ return;
+ }
+
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Value '$payload' is not a valid length for a bulk response."
+ ));
+
+ return;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php
new file mode 100644
index 0000000..3e18b7b
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/ErrorResponse.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Response\Error;
+
+/**
+ * Handler for the error response type in the standard Redis wire protocol.
+ * It translates the payload to a complex response object for Predis.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ErrorResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ return new Error($payload);
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php
new file mode 100644
index 0000000..f965601
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/IntegerResponse.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+
+/**
+ * Handler for the integer response type in the standard Redis wire protocol.
+ * It translates the payload an integer or NULL.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class IntegerResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ if (is_numeric($payload)) {
+ $integer = (int) $payload;
+ return $integer == $payload ? $integer : $payload;
+ }
+
+ if ($payload !== 'nil') {
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Cannot parse '$payload' as a valid numeric response."
+ ));
+ }
+
+ return;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php
new file mode 100644
index 0000000..820b9b4
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/MultiBulkResponse.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+
+/**
+ * Handler for the multibulk response type in the standard Redis wire protocol.
+ * It returns multibulk responses as PHP arrays.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MultiBulkResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ $length = (int) $payload;
+
+ if ("$length" !== $payload) {
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Cannot parse '$payload' as a valid length of a multi-bulk response."
+ ));
+ }
+
+ if ($length === -1) {
+ return;
+ }
+
+ $list = array();
+
+ if ($length > 0) {
+ $handlersCache = array();
+ $reader = $connection->getProtocol()->getResponseReader();
+
+ for ($i = 0; $i < $length; ++$i) {
+ $header = $connection->readLine();
+ $prefix = $header[0];
+
+ if (isset($handlersCache[$prefix])) {
+ $handler = $handlersCache[$prefix];
+ } else {
+ $handler = $reader->getHandler($prefix);
+ $handlersCache[$prefix] = $handler;
+ }
+
+ $list[$i] = $handler->handle($connection, substr($header, 1));
+ }
+ }
+
+ return $list;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php b/vendor/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php
new file mode 100644
index 0000000..ca08a9c
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/ResponseHandlerInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\Connection\CompositeConnectionInterface;
+
+/**
+ * Defines a pluggable handler used to parse a particular type of response.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ResponseHandlerInterface
+{
+ /**
+ * Deserializes a response returned by Redis and reads more data from the
+ * connection if needed.
+ *
+ * @param CompositeConnectionInterface $connection Redis connection.
+ * @param string $payload String payload.
+ *
+ * @return mixed
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload);
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/StatusResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/StatusResponse.php
new file mode 100644
index 0000000..7bde555
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/StatusResponse.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Response\Status;
+
+/**
+ * Handler for the status response type in the standard Redis wire protocol. It
+ * translates certain classes of status response to PHP objects or just returns
+ * the payload as a string.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StatusResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ return Status::get($payload);
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php b/vendor/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php
new file mode 100644
index 0000000..7cdb736
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/Handler/StreamableMultiBulkResponse.php
@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text\Handler;
+
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;
+
+/**
+ * Handler for the multibulk response type in the standard Redis wire protocol.
+ * It returns multibulk responses as iterators that can stream bulk elements.
+ *
+ * Streamable multibulk responses are not globally supported by the abstractions
+ * built-in into Predis, such as transactions or pipelines. Use them with care!
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class StreamableMultiBulkResponse implements ResponseHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(CompositeConnectionInterface $connection, $payload)
+ {
+ $length = (int) $payload;
+
+ if ("$length" != $payload) {
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Cannot parse '$payload' as a valid length for a multi-bulk response."
+ ));
+ }
+
+ return new MultiBulkIterator($connection, $length);
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/ProtocolProcessor.php b/vendor/predis/predis/src/Protocol/Text/ProtocolProcessor.php
new file mode 100644
index 0000000..99acdf8
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/ProtocolProcessor.php
@@ -0,0 +1,123 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text;
+
+use Predis\Command\CommandInterface;
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+use Predis\Protocol\ProtocolProcessorInterface;
+use Predis\Response\Error as ErrorResponse;
+use Predis\Response\Iterator\MultiBulk as MultiBulkIterator;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * Protocol processor for the standard Redis wire protocol.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ProtocolProcessor implements ProtocolProcessorInterface
+{
+ protected $mbiterable;
+ protected $serializer;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->mbiterable = false;
+ $this->serializer = new RequestSerializer();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write(CompositeConnectionInterface $connection, CommandInterface $command)
+ {
+ $request = $this->serializer->serialize($command);
+ $connection->writeBuffer($request);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read(CompositeConnectionInterface $connection)
+ {
+ $chunk = $connection->readLine();
+ $prefix = $chunk[0];
+ $payload = substr($chunk, 1);
+
+ switch ($prefix) {
+ case '+':
+ return new StatusResponse($payload);
+
+ case '$':
+ $size = (int) $payload;
+ if ($size === -1) {
+ return;
+ }
+
+ return substr($connection->readBuffer($size + 2), 0, -2);
+
+ case '*':
+ $count = (int) $payload;
+
+ if ($count === -1) {
+ return;
+ }
+ if ($this->mbiterable) {
+ return new MultiBulkIterator($connection, $count);
+ }
+
+ $multibulk = array();
+
+ for ($i = 0; $i < $count; ++$i) {
+ $multibulk[$i] = $this->read($connection);
+ }
+
+ return $multibulk;
+
+ case ':':
+ $integer = (int) $payload;
+ return $integer == $payload ? $integer : $payload;
+
+ case '-':
+ return new ErrorResponse($payload);
+
+ default:
+ CommunicationException::handle(new ProtocolException(
+ $connection, "Unknown response prefix: '$prefix'."
+ ));
+
+ return;
+ }
+ }
+
+ /**
+ * Enables or disables returning multibulk responses as specialized PHP
+ * iterators used to stream bulk elements of a multibulk response instead
+ * returning a plain array.
+ *
+ * Streamable multibulk responses are not globally supported by the
+ * abstractions built-in into Predis, such as transactions or pipelines.
+ * Use them with care!
+ *
+ * @param bool $value Enable or disable streamable multibulk responses.
+ */
+ public function useIterableMultibulk($value)
+ {
+ $this->mbiterable = (bool) $value;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/RequestSerializer.php b/vendor/predis/predis/src/Protocol/Text/RequestSerializer.php
new file mode 100644
index 0000000..859595b
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/RequestSerializer.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text;
+
+use Predis\Command\CommandInterface;
+use Predis\Protocol\RequestSerializerInterface;
+
+/**
+ * Request serializer for the standard Redis wire protocol.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RequestSerializer implements RequestSerializerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function serialize(CommandInterface $command)
+ {
+ $commandID = $command->getId();
+ $arguments = $command->getArguments();
+
+ $cmdlen = strlen($commandID);
+ $reqlen = count($arguments) + 1;
+
+ $buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandID}\r\n";
+
+ foreach ($arguments as $argument) {
+ $arglen = strlen($argument);
+ $buffer .= "\${$arglen}\r\n{$argument}\r\n";
+ }
+
+ return $buffer;
+ }
+}
diff --git a/vendor/predis/predis/src/Protocol/Text/ResponseReader.php b/vendor/predis/predis/src/Protocol/Text/ResponseReader.php
new file mode 100644
index 0000000..d96218d
--- /dev/null
+++ b/vendor/predis/predis/src/Protocol/Text/ResponseReader.php
@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Protocol\Text;
+
+use Predis\CommunicationException;
+use Predis\Connection\CompositeConnectionInterface;
+use Predis\Protocol\ProtocolException;
+use Predis\Protocol\ResponseReaderInterface;
+
+/**
+ * Response reader for the standard Redis wire protocol.
+ *
+ * @link http://redis.io/topics/protocol
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ResponseReader implements ResponseReaderInterface
+{
+ protected $handlers;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->handlers = $this->getDefaultHandlers();
+ }
+
+ /**
+ * Returns the default handlers for the supported type of responses.
+ *
+ * @return array
+ */
+ protected function getDefaultHandlers()
+ {
+ return array(
+ '+' => new Handler\StatusResponse(),
+ '-' => new Handler\ErrorResponse(),
+ ':' => new Handler\IntegerResponse(),
+ '$' => new Handler\BulkResponse(),
+ '*' => new Handler\MultiBulkResponse(),
+ );
+ }
+
+ /**
+ * Sets the handler for the specified prefix identifying the response type.
+ *
+ * @param string $prefix Identifier of the type of response.
+ * @param Handler\ResponseHandlerInterface $handler Response handler.
+ */
+ public function setHandler($prefix, Handler\ResponseHandlerInterface $handler)
+ {
+ $this->handlers[$prefix] = $handler;
+ }
+
+ /**
+ * Returns the response handler associated to a certain type of response.
+ *
+ * @param string $prefix Identifier of the type of response.
+ *
+ * @return Handler\ResponseHandlerInterface
+ */
+ public function getHandler($prefix)
+ {
+ if (isset($this->handlers[$prefix])) {
+ return $this->handlers[$prefix];
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read(CompositeConnectionInterface $connection)
+ {
+ $header = $connection->readLine();
+
+ if ($header === '') {
+ $this->onProtocolError($connection, 'Unexpected empty reponse header.');
+ }
+
+ $prefix = $header[0];
+
+ if (!isset($this->handlers[$prefix])) {
+ $this->onProtocolError($connection, "Unknown response prefix: '$prefix'.");
+ }
+
+ $payload = $this->handlers[$prefix]->handle($connection, substr($header, 1));
+
+ return $payload;
+ }
+
+ /**
+ * Handles protocol errors generated while reading responses from a
+ * connection.
+ *
+ * @param CompositeConnectionInterface $connection Redis connection that generated the error.
+ * @param string $message Error message.
+ */
+ protected function onProtocolError(CompositeConnectionInterface $connection, $message)
+ {
+ CommunicationException::handle(
+ new ProtocolException($connection, $message)
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/PubSub/AbstractConsumer.php b/vendor/predis/predis/src/PubSub/AbstractConsumer.php
new file mode 100644
index 0000000..d9ce588
--- /dev/null
+++ b/vendor/predis/predis/src/PubSub/AbstractConsumer.php
@@ -0,0 +1,224 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\PubSub;
+
+/**
+ * Base implementation of a PUB/SUB consumer abstraction based on PHP iterators.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class AbstractConsumer implements \Iterator
+{
+ const SUBSCRIBE = 'subscribe';
+ const UNSUBSCRIBE = 'unsubscribe';
+ const PSUBSCRIBE = 'psubscribe';
+ const PUNSUBSCRIBE = 'punsubscribe';
+ const MESSAGE = 'message';
+ const PMESSAGE = 'pmessage';
+ const PONG = 'pong';
+
+ const STATUS_VALID = 1; // 0b0001
+ const STATUS_SUBSCRIBED = 2; // 0b0010
+ const STATUS_PSUBSCRIBED = 4; // 0b0100
+
+ private $position = null;
+ private $statusFlags = self::STATUS_VALID;
+
+ /**
+ * Automatically stops the consumer when the garbage collector kicks in.
+ */
+ public function __destruct()
+ {
+ $this->stop(true);
+ }
+
+ /**
+ * Checks if the specified flag is valid based on the state of the consumer.
+ *
+ * @param int $value Flag.
+ *
+ * @return bool
+ */
+ protected function isFlagSet($value)
+ {
+ return ($this->statusFlags & $value) === $value;
+ }
+
+ /**
+ * Subscribes to the specified channels.
+ *
+ * @param mixed $channel,... One or more channel names.
+ */
+ public function subscribe($channel /*, ... */)
+ {
+ $this->writeRequest(self::SUBSCRIBE, func_get_args());
+ $this->statusFlags |= self::STATUS_SUBSCRIBED;
+ }
+
+ /**
+ * Unsubscribes from the specified channels.
+ *
+ * @param string ... One or more channel names.
+ */
+ public function unsubscribe(/* ... */)
+ {
+ $this->writeRequest(self::UNSUBSCRIBE, func_get_args());
+ }
+
+ /**
+ * Subscribes to the specified channels using a pattern.
+ *
+ * @param mixed $pattern,... One or more channel name patterns.
+ */
+ public function psubscribe($pattern /* ... */)
+ {
+ $this->writeRequest(self::PSUBSCRIBE, func_get_args());
+ $this->statusFlags |= self::STATUS_PSUBSCRIBED;
+ }
+
+ /**
+ * Unsubscribes from the specified channels using a pattern.
+ *
+ * @param string ... One or more channel name patterns.
+ */
+ public function punsubscribe(/* ... */)
+ {
+ $this->writeRequest(self::PUNSUBSCRIBE, func_get_args());
+ }
+
+ /**
+ * PING the server with an optional payload that will be echoed as a
+ * PONG message in the pub/sub loop.
+ *
+ * @param string $payload Optional PING payload.
+ */
+ public function ping($payload = null)
+ {
+ $this->writeRequest('PING', array($payload));
+ }
+
+ /**
+ * Closes the context by unsubscribing from all the subscribed channels. The
+ * context can be forcefully closed by dropping the underlying connection.
+ *
+ * @param bool $drop Indicates if the context should be closed by dropping the connection.
+ *
+ * @return bool Returns false when there are no pending messages.
+ */
+ public function stop($drop = false)
+ {
+ if (!$this->valid()) {
+ return false;
+ }
+
+ if ($drop) {
+ $this->invalidate();
+ $this->disconnect();
+ } else {
+ if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) {
+ $this->unsubscribe();
+ }
+ if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) {
+ $this->punsubscribe();
+ }
+ }
+
+ return !$drop;
+ }
+
+ /**
+ * Closes the underlying connection when forcing a disconnection.
+ */
+ abstract protected function disconnect();
+
+ /**
+ * Writes a Redis command on the underlying connection.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ */
+ abstract protected function writeRequest($method, $arguments);
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ // NOOP
+ }
+
+ /**
+ * Returns the last message payload retrieved from the server and generated
+ * by one of the active subscriptions.
+ *
+ * @return array
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ if ($this->valid()) {
+ ++$this->position;
+ }
+
+ return $this->position;
+ }
+
+ /**
+ * Checks if the the consumer is still in a valid state to continue.
+ *
+ * @return bool
+ */
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ $isValid = $this->isFlagSet(self::STATUS_VALID);
+ $subscriptionFlags = self::STATUS_SUBSCRIBED | self::STATUS_PSUBSCRIBED;
+ $hasSubscriptions = ($this->statusFlags & $subscriptionFlags) > 0;
+
+ return $isValid && $hasSubscriptions;
+ }
+
+ /**
+ * Resets the state of the consumer.
+ */
+ protected function invalidate()
+ {
+ $this->statusFlags = 0; // 0b0000;
+ }
+
+ /**
+ * Waits for a new message from the server generated by one of the active
+ * subscriptions and returns it when available.
+ *
+ * @return array
+ */
+ abstract protected function getValue();
+}
diff --git a/vendor/predis/predis/src/PubSub/Consumer.php b/vendor/predis/predis/src/PubSub/Consumer.php
new file mode 100644
index 0000000..5f2d8a8
--- /dev/null
+++ b/vendor/predis/predis/src/PubSub/Consumer.php
@@ -0,0 +1,158 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\PubSub;
+
+use Predis\ClientException;
+use Predis\ClientInterface;
+use Predis\Command\Command;
+use Predis\Connection\AggregateConnectionInterface;
+use Predis\NotSupportedException;
+
+/**
+ * PUB/SUB consumer abstraction.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Consumer extends AbstractConsumer
+{
+ private $client;
+ private $options;
+
+ /**
+ * @param ClientInterface $client Client instance used by the consumer.
+ * @param array $options Options for the consumer initialization.
+ */
+ public function __construct(ClientInterface $client, array $options = null)
+ {
+ $this->checkCapabilities($client);
+
+ $this->options = $options ?: array();
+ $this->client = $client;
+
+ $this->genericSubscribeInit('subscribe');
+ $this->genericSubscribeInit('psubscribe');
+ }
+
+ /**
+ * Returns the underlying client instance used by the pub/sub iterator.
+ *
+ * @return ClientInterface
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * Checks if the client instance satisfies the required conditions needed to
+ * initialize a PUB/SUB consumer.
+ *
+ * @param ClientInterface $client Client instance used by the consumer.
+ *
+ * @throws NotSupportedException
+ */
+ private function checkCapabilities(ClientInterface $client)
+ {
+ if ($client->getConnection() instanceof AggregateConnectionInterface) {
+ throw new NotSupportedException(
+ 'Cannot initialize a PUB/SUB consumer over aggregate connections.'
+ );
+ }
+
+ $commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe');
+
+ if ($client->getProfile()->supportsCommands($commands) === false) {
+ throw new NotSupportedException(
+ 'The current profile does not support PUB/SUB related commands.'
+ );
+ }
+ }
+
+ /**
+ * This method shares the logic to handle both SUBSCRIBE and PSUBSCRIBE.
+ *
+ * @param string $subscribeAction Type of subscription.
+ */
+ private function genericSubscribeInit($subscribeAction)
+ {
+ if (isset($this->options[$subscribeAction])) {
+ $this->$subscribeAction($this->options[$subscribeAction]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeRequest($method, $arguments)
+ {
+ $this->client->getConnection()->writeRequest(
+ $this->client->createCommand($method,
+ Command::normalizeArguments($arguments)
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function disconnect()
+ {
+ $this->client->disconnect();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getValue()
+ {
+ $response = $this->client->getConnection()->read();
+
+ switch ($response[0]) {
+ case self::SUBSCRIBE:
+ case self::UNSUBSCRIBE:
+ case self::PSUBSCRIBE:
+ case self::PUNSUBSCRIBE:
+ if ($response[2] === 0) {
+ $this->invalidate();
+ }
+ // The missing break here is intentional as we must process
+ // subscriptions and unsubscriptions as standard messages.
+ // no break
+
+ case self::MESSAGE:
+ return (object) array(
+ 'kind' => $response[0],
+ 'channel' => $response[1],
+ 'payload' => $response[2],
+ );
+
+ case self::PMESSAGE:
+ return (object) array(
+ 'kind' => $response[0],
+ 'pattern' => $response[1],
+ 'channel' => $response[2],
+ 'payload' => $response[3],
+ );
+
+ case self::PONG:
+ return (object) array(
+ 'kind' => $response[0],
+ 'payload' => $response[1],
+ );
+
+ default:
+ throw new ClientException(
+ "Unknown message type '{$response[0]}' received in the PUB/SUB context."
+ );
+ }
+ }
+}
diff --git a/vendor/predis/predis/src/PubSub/DispatcherLoop.php b/vendor/predis/predis/src/PubSub/DispatcherLoop.php
new file mode 100644
index 0000000..d0369e7
--- /dev/null
+++ b/vendor/predis/predis/src/PubSub/DispatcherLoop.php
@@ -0,0 +1,170 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\PubSub;
+
+/**
+ * Method-dispatcher loop built around the client-side abstraction of a Redis
+ * PUB / SUB context.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class DispatcherLoop
+{
+ private $pubsub;
+
+ protected $callbacks;
+ protected $defaultCallback;
+ protected $subscriptionCallback;
+
+ /**
+ * @param Consumer $pubsub PubSub consumer instance used by the loop.
+ */
+ public function __construct(Consumer $pubsub)
+ {
+ $this->callbacks = array();
+ $this->pubsub = $pubsub;
+ }
+
+ /**
+ * Checks if the passed argument is a valid callback.
+ *
+ * @param mixed $callable A callback.
+ *
+ * @throws \InvalidArgumentException
+ */
+ protected function assertCallback($callable)
+ {
+ if (!is_callable($callable)) {
+ throw new \InvalidArgumentException('The given argument must be a callable object.');
+ }
+ }
+
+ /**
+ * Returns the underlying PUB / SUB context.
+ *
+ * @return Consumer
+ */
+ public function getPubSubConsumer()
+ {
+ return $this->pubsub;
+ }
+
+ /**
+ * Sets a callback that gets invoked upon new subscriptions.
+ *
+ * @param mixed $callable A callback.
+ */
+ public function subscriptionCallback($callable = null)
+ {
+ if (isset($callable)) {
+ $this->assertCallback($callable);
+ }
+
+ $this->subscriptionCallback = $callable;
+ }
+
+ /**
+ * Sets a callback that gets invoked when a message is received on a
+ * channel that does not have an associated callback.
+ *
+ * @param mixed $callable A callback.
+ */
+ public function defaultCallback($callable = null)
+ {
+ if (isset($callable)) {
+ $this->assertCallback($callable);
+ }
+
+ $this->subscriptionCallback = $callable;
+ }
+
+ /**
+ * Binds a callback to a channel.
+ *
+ * @param string $channel Channel name.
+ * @param callable $callback A callback.
+ */
+ public function attachCallback($channel, $callback)
+ {
+ $callbackName = $this->getPrefixKeys().$channel;
+
+ $this->assertCallback($callback);
+ $this->callbacks[$callbackName] = $callback;
+ $this->pubsub->subscribe($channel);
+ }
+
+ /**
+ * Stops listening to a channel and removes the associated callback.
+ *
+ * @param string $channel Redis channel.
+ */
+ public function detachCallback($channel)
+ {
+ $callbackName = $this->getPrefixKeys().$channel;
+
+ if (isset($this->callbacks[$callbackName])) {
+ unset($this->callbacks[$callbackName]);
+ $this->pubsub->unsubscribe($channel);
+ }
+ }
+
+ /**
+ * Starts the dispatcher loop.
+ */
+ public function run()
+ {
+ foreach ($this->pubsub as $message) {
+ $kind = $message->kind;
+
+ if ($kind !== Consumer::MESSAGE && $kind !== Consumer::PMESSAGE) {
+ if (isset($this->subscriptionCallback)) {
+ $callback = $this->subscriptionCallback;
+ call_user_func($callback, $message);
+ }
+
+ continue;
+ }
+
+ if (isset($this->callbacks[$message->channel])) {
+ $callback = $this->callbacks[$message->channel];
+ call_user_func($callback, $message->payload);
+ } elseif (isset($this->defaultCallback)) {
+ $callback = $this->defaultCallback;
+ call_user_func($callback, $message);
+ }
+ }
+ }
+
+ /**
+ * Terminates the dispatcher loop.
+ */
+ public function stop()
+ {
+ $this->pubsub->stop();
+ }
+
+ /**
+ * Return the prefix used for keys.
+ *
+ * @return string
+ */
+ protected function getPrefixKeys()
+ {
+ $options = $this->pubsub->getClient()->getOptions();
+
+ if (isset($options->prefix)) {
+ return $options->prefix->getPrefix();
+ }
+
+ return '';
+ }
+}
diff --git a/vendor/predis/predis/src/Replication/MissingMasterException.php b/vendor/predis/predis/src/Replication/MissingMasterException.php
new file mode 100644
index 0000000..223bd2d
--- /dev/null
+++ b/vendor/predis/predis/src/Replication/MissingMasterException.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Replication;
+
+use Predis\ClientException;
+
+/**
+ * Exception class that identifies when master is missing in a replication setup.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MissingMasterException extends ClientException
+{
+}
diff --git a/vendor/predis/predis/src/Replication/ReplicationStrategy.php b/vendor/predis/predis/src/Replication/ReplicationStrategy.php
new file mode 100644
index 0000000..8f826b4
--- /dev/null
+++ b/vendor/predis/predis/src/Replication/ReplicationStrategy.php
@@ -0,0 +1,279 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Replication;
+
+use Predis\Command\CommandInterface;
+use Predis\NotSupportedException;
+
+/**
+ * Defines a strategy for master/slave replication.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ReplicationStrategy
+{
+ protected $disallowed;
+ protected $readonly;
+ protected $readonlySHA1;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->disallowed = $this->getDisallowedOperations();
+ $this->readonly = $this->getReadOnlyOperations();
+ $this->readonlySHA1 = array();
+ }
+
+ /**
+ * Returns if the specified command will perform a read-only operation
+ * on Redis or not.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @throws NotSupportedException
+ *
+ * @return bool
+ */
+ public function isReadOperation(CommandInterface $command)
+ {
+ if (isset($this->disallowed[$id = $command->getId()])) {
+ throw new NotSupportedException(
+ "The command '$id' is not allowed in replication mode."
+ );
+ }
+
+ if (isset($this->readonly[$id])) {
+ if (true === $readonly = $this->readonly[$id]) {
+ return true;
+ }
+
+ return call_user_func($readonly, $command);
+ }
+
+ if (($eval = $id === 'EVAL') || $id === 'EVALSHA') {
+ $argument = $command->getArgument(0);
+ $sha1 = $eval ? sha1(strval($argument)) : $argument;
+
+ if (isset($this->readonlySHA1[$sha1])) {
+ if (true === $readonly = $this->readonlySHA1[$sha1]) {
+ return true;
+ }
+
+ return call_user_func($readonly, $command);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns if the specified command is not allowed for execution in a master
+ * / slave replication context.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return bool
+ */
+ public function isDisallowedOperation(CommandInterface $command)
+ {
+ return isset($this->disallowed[$command->getId()]);
+ }
+
+ /**
+ * Checks if BITFIELD performs a read-only operation by looking for certain
+ * SET and INCRYBY modifiers in the arguments array of the command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return bool
+ */
+ protected function isBitfieldReadOnly(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $argc = count($arguments);
+
+ if ($argc >= 2) {
+ for ($i = 1; $i < $argc; ++$i) {
+ $argument = strtoupper($arguments[$i]);
+ if ($argument === 'SET' || $argument === 'INCRBY') {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a GEORADIUS command is a readable operation by parsing the
+ * arguments array of the specified commad instance.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @return bool
+ */
+ protected function isGeoradiusReadOnly(CommandInterface $command)
+ {
+ $arguments = $command->getArguments();
+ $argc = count($arguments);
+ $startIndex = $command->getId() === 'GEORADIUS' ? 5 : 4;
+
+ if ($argc > $startIndex) {
+ for ($i = $startIndex; $i < $argc; ++$i) {
+ $argument = strtoupper($arguments[$i]);
+ if ($argument === 'STORE' || $argument === 'STOREDIST') {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Marks a command as a read-only operation.
+ *
+ * When the behavior of a command can be decided only at runtime depending
+ * on its arguments, a callable object can be provided to dynamically check
+ * if the specified command performs a read or a write operation.
+ *
+ * @param string $commandID Command ID.
+ * @param mixed $readonly A boolean value or a callable object.
+ */
+ public function setCommandReadOnly($commandID, $readonly = true)
+ {
+ $commandID = strtoupper($commandID);
+
+ if ($readonly) {
+ $this->readonly[$commandID] = $readonly;
+ } else {
+ unset($this->readonly[$commandID]);
+ }
+ }
+
+ /**
+ * Marks a Lua script for EVAL and EVALSHA as a read-only operation. When
+ * the behaviour of a script can be decided only at runtime depending on
+ * its arguments, a callable object can be provided to dynamically check
+ * if the passed instance of EVAL or EVALSHA performs write operations or
+ * not.
+ *
+ * @param string $script Body of the Lua script.
+ * @param mixed $readonly A boolean value or a callable object.
+ */
+ public function setScriptReadOnly($script, $readonly = true)
+ {
+ $sha1 = sha1($script);
+
+ if ($readonly) {
+ $this->readonlySHA1[$sha1] = $readonly;
+ } else {
+ unset($this->readonlySHA1[$sha1]);
+ }
+ }
+
+ /**
+ * Returns the default list of disallowed commands.
+ *
+ * @return array
+ */
+ protected function getDisallowedOperations()
+ {
+ return array(
+ 'SHUTDOWN' => true,
+ 'INFO' => true,
+ 'DBSIZE' => true,
+ 'LASTSAVE' => true,
+ 'CONFIG' => true,
+ 'MONITOR' => true,
+ 'SLAVEOF' => true,
+ 'SAVE' => true,
+ 'BGSAVE' => true,
+ 'BGREWRITEAOF' => true,
+ 'SLOWLOG' => true,
+ );
+ }
+
+ /**
+ * Returns the default list of commands performing read-only operations.
+ *
+ * @return array
+ */
+ protected function getReadOnlyOperations()
+ {
+ return array(
+ 'EXISTS' => true,
+ 'TYPE' => true,
+ 'KEYS' => true,
+ 'SCAN' => true,
+ 'RANDOMKEY' => true,
+ 'TTL' => true,
+ 'GET' => true,
+ 'MGET' => true,
+ 'SUBSTR' => true,
+ 'STRLEN' => true,
+ 'GETRANGE' => true,
+ 'GETBIT' => true,
+ 'LLEN' => true,
+ 'LRANGE' => true,
+ 'LINDEX' => true,
+ 'SCARD' => true,
+ 'SISMEMBER' => true,
+ 'SINTER' => true,
+ 'SUNION' => true,
+ 'SDIFF' => true,
+ 'SMEMBERS' => true,
+ 'SSCAN' => true,
+ 'SRANDMEMBER' => true,
+ 'ZRANGE' => true,
+ 'ZREVRANGE' => true,
+ 'ZRANGEBYSCORE' => true,
+ 'ZREVRANGEBYSCORE' => true,
+ 'ZCARD' => true,
+ 'ZSCORE' => true,
+ 'ZCOUNT' => true,
+ 'ZRANK' => true,
+ 'ZREVRANK' => true,
+ 'ZSCAN' => true,
+ 'ZLEXCOUNT' => true,
+ 'ZRANGEBYLEX' => true,
+ 'ZREVRANGEBYLEX' => true,
+ 'HGET' => true,
+ 'HMGET' => true,
+ 'HEXISTS' => true,
+ 'HLEN' => true,
+ 'HKEYS' => true,
+ 'HVALS' => true,
+ 'HGETALL' => true,
+ 'HSCAN' => true,
+ 'HSTRLEN' => true,
+ 'PING' => true,
+ 'AUTH' => true,
+ 'SELECT' => true,
+ 'ECHO' => true,
+ 'QUIT' => true,
+ 'OBJECT' => true,
+ 'BITCOUNT' => true,
+ 'BITPOS' => true,
+ 'TIME' => true,
+ 'PFCOUNT' => true,
+ 'BITFIELD' => array($this, 'isBitfieldReadOnly'),
+ 'GEOHASH' => true,
+ 'GEOPOS' => true,
+ 'GEODIST' => true,
+ 'GEORADIUS' => array($this, 'isGeoradiusReadOnly'),
+ 'GEORADIUSBYMEMBER' => array($this, 'isGeoradiusReadOnly'),
+ );
+ }
+}
diff --git a/vendor/predis/predis/src/Replication/RoleException.php b/vendor/predis/predis/src/Replication/RoleException.php
new file mode 100644
index 0000000..0d9954b
--- /dev/null
+++ b/vendor/predis/predis/src/Replication/RoleException.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Replication;
+
+use Predis\CommunicationException;
+
+/**
+ * Exception class that identifies a role mismatch when connecting to node
+ * managed by redis-sentinel.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RoleException extends CommunicationException
+{
+}
diff --git a/vendor/predis/predis/src/Response/Error.php b/vendor/predis/predis/src/Response/Error.php
new file mode 100644
index 0000000..3933857
--- /dev/null
+++ b/vendor/predis/predis/src/Response/Error.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response;
+
+/**
+ * Represents an error returned by Redis (-ERR responses) during the execution
+ * of a command on the server.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Error implements ErrorInterface
+{
+ private $message;
+
+ /**
+ * @param string $message Error message returned by Redis
+ */
+ public function __construct($message)
+ {
+ $this->message = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getErrorType()
+ {
+ list($errorType) = explode(' ', $this->getMessage(), 2);
+
+ return $errorType;
+ }
+
+ /**
+ * Converts the object to its string representation.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getMessage();
+ }
+}
diff --git a/vendor/predis/predis/src/Response/ErrorInterface.php b/vendor/predis/predis/src/Response/ErrorInterface.php
new file mode 100644
index 0000000..a4a4a02
--- /dev/null
+++ b/vendor/predis/predis/src/Response/ErrorInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response;
+
+/**
+ * Represents an error returned by Redis (responses identified by "-" in the
+ * Redis protocol) during the execution of an operation on the server.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ErrorInterface extends ResponseInterface
+{
+ /**
+ * Returns the error message.
+ *
+ * @return string
+ */
+ public function getMessage();
+
+ /**
+ * Returns the error type (e.g. ERR, ASK, MOVED).
+ *
+ * @return string
+ */
+ public function getErrorType();
+}
diff --git a/vendor/predis/predis/src/Response/Iterator/MultiBulk.php b/vendor/predis/predis/src/Response/Iterator/MultiBulk.php
new file mode 100644
index 0000000..b1d2924
--- /dev/null
+++ b/vendor/predis/predis/src/Response/Iterator/MultiBulk.php
@@ -0,0 +1,77 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response\Iterator;
+
+use Predis\Connection\NodeConnectionInterface;
+
+/**
+ * Streamable multibulk response.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MultiBulk extends MultiBulkIterator
+{
+ private $connection;
+
+ /**
+ * @param NodeConnectionInterface $connection Connection to Redis.
+ * @param int $size Number of elements of the multibulk response.
+ */
+ public function __construct(NodeConnectionInterface $connection, $size)
+ {
+ $this->connection = $connection;
+ $this->size = $size;
+ $this->position = 0;
+ $this->current = $size > 0 ? $this->getValue() : null;
+ }
+
+ /**
+ * Handles the synchronization of the client with the Redis protocol when
+ * the garbage collector kicks in (e.g. when the iterator goes out of the
+ * scope of a foreach or it is unset).
+ */
+ public function __destruct()
+ {
+ $this->drop(true);
+ }
+
+ /**
+ * Drop queued elements that have not been read from the connection either
+ * by consuming the rest of the multibulk response or quickly by closing the
+ * underlying connection.
+ *
+ * @param bool $disconnect Consume the iterator or drop the connection.
+ */
+ public function drop($disconnect = false)
+ {
+ if ($disconnect) {
+ if ($this->valid()) {
+ $this->position = $this->size;
+ $this->connection->disconnect();
+ }
+ } else {
+ while ($this->valid()) {
+ $this->next();
+ }
+ }
+ }
+
+ /**
+ * Reads the next item of the multibulk response from the connection.
+ *
+ * @return mixed
+ */
+ protected function getValue()
+ {
+ return $this->connection->read();
+ }
+}
diff --git a/vendor/predis/predis/src/Response/Iterator/MultiBulkIterator.php b/vendor/predis/predis/src/Response/Iterator/MultiBulkIterator.php
new file mode 100644
index 0000000..bac0ac9
--- /dev/null
+++ b/vendor/predis/predis/src/Response/Iterator/MultiBulkIterator.php
@@ -0,0 +1,110 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response\Iterator;
+
+use Predis\Response\ResponseInterface;
+
+/**
+ * Iterator that abstracts the access to multibulk responses allowing them to be
+ * consumed in a streamable fashion without keeping the whole payload in memory.
+ *
+ * This iterator does not support rewinding which means that the iteration, once
+ * consumed, cannot be restarted.
+ *
+ * Always make sure that the whole iteration is consumed (or dropped) to prevent
+ * protocol desynchronization issues.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+abstract class MultiBulkIterator implements \Iterator, \Countable, ResponseInterface
+{
+ protected $current;
+ protected $position;
+ protected $size;
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function rewind()
+ {
+ // NOOP
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function current()
+ {
+ return $this->current;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function key()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function next()
+ {
+ if (++$this->position < $this->size) {
+ $this->current = $this->getValue();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function valid()
+ {
+ return $this->position < $this->size;
+ }
+
+ /**
+ * Returns the number of items comprising the whole multibulk response.
+ *
+ * This method should be used instead of iterator_count() to get the size of
+ * the current multibulk response since the former consumes the iteration to
+ * count the number of elements, but our iterators do not support rewinding.
+ *
+ * @return int
+ */
+ #[\ReturnTypeWillChange]
+ public function count()
+ {
+ return $this->size;
+ }
+
+ /**
+ * Returns the current position of the iterator.
+ *
+ * @return int
+ */
+ public function getPosition()
+ {
+ return $this->position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ abstract protected function getValue();
+}
diff --git a/vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php b/vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php
new file mode 100644
index 0000000..ed3f88e
--- /dev/null
+++ b/vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php
@@ -0,0 +1,91 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response\Iterator;
+
+/**
+ * Outer iterator consuming streamable multibulk responses by yielding tuples of
+ * keys and values.
+ *
+ * This wrapper is useful for responses to commands such as `HGETALL` that can
+ * be iterater as $key => $value pairs.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MultiBulkTuple extends MultiBulk implements \OuterIterator
+{
+ private $iterator;
+
+ /**
+ * @param MultiBulk $iterator Inner multibulk response iterator.
+ */
+ public function __construct(MultiBulk $iterator)
+ {
+ $this->checkPreconditions($iterator);
+
+ $this->size = count($iterator) / 2;
+ $this->iterator = $iterator;
+ $this->position = $iterator->getPosition();
+ $this->current = $this->size > 0 ? $this->getValue() : null;
+ }
+
+ /**
+ * Checks for valid preconditions.
+ *
+ * @param MultiBulk $iterator Inner multibulk response iterator.
+ *
+ * @throws \InvalidArgumentException
+ * @throws \UnexpectedValueException
+ */
+ protected function checkPreconditions(MultiBulk $iterator)
+ {
+ if ($iterator->getPosition() !== 0) {
+ throw new \InvalidArgumentException(
+ 'Cannot initialize a tuple iterator using an already initiated iterator.'
+ );
+ }
+
+ if (($size = count($iterator)) % 2 !== 0) {
+ throw new \UnexpectedValueException('Invalid response size for a tuple iterator.');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function getInnerIterator()
+ {
+ return $this->iterator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __destruct()
+ {
+ $this->iterator->drop(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getValue()
+ {
+ $k = $this->iterator->current();
+ $this->iterator->next();
+
+ $v = $this->iterator->current();
+ $this->iterator->next();
+
+ return array($k, $v);
+ }
+}
diff --git a/vendor/predis/predis/src/Response/ResponseInterface.php b/vendor/predis/predis/src/Response/ResponseInterface.php
new file mode 100644
index 0000000..0af1357
--- /dev/null
+++ b/vendor/predis/predis/src/Response/ResponseInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response;
+
+/**
+ * Represents a complex response object from Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+interface ResponseInterface
+{
+}
diff --git a/vendor/predis/predis/src/Response/ServerException.php b/vendor/predis/predis/src/Response/ServerException.php
new file mode 100644
index 0000000..407dc5b
--- /dev/null
+++ b/vendor/predis/predis/src/Response/ServerException.php
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response;
+
+use Predis\PredisException;
+
+/**
+ * Exception class that identifies server-side Redis errors.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class ServerException extends PredisException implements ErrorInterface
+{
+ /**
+ * Gets the type of the error returned by Redis.
+ *
+ * @return string
+ */
+ public function getErrorType()
+ {
+ list($errorType) = explode(' ', $this->getMessage(), 2);
+
+ return $errorType;
+ }
+
+ /**
+ * Converts the exception to an instance of Predis\Response\Error.
+ *
+ * @return Error
+ */
+ public function toErrorResponse()
+ {
+ return new Error($this->getMessage());
+ }
+}
diff --git a/vendor/predis/predis/src/Response/Status.php b/vendor/predis/predis/src/Response/Status.php
new file mode 100644
index 0000000..729bb66
--- /dev/null
+++ b/vendor/predis/predis/src/Response/Status.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Response;
+
+/**
+ * Represents a status response returned by Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Status implements ResponseInterface
+{
+ private static $OK;
+ private static $QUEUED;
+
+ private $payload;
+
+ /**
+ * @param string $payload Payload of the status response as returned by Redis.
+ */
+ public function __construct($payload)
+ {
+ $this->payload = $payload;
+ }
+
+ /**
+ * Converts the response object to its string representation.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * Returns the payload of status response.
+ *
+ * @return string
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * Returns an instance of a status response object.
+ *
+ * Common status responses such as OK or QUEUED are cached in order to lower
+ * the global memory usage especially when using pipelines.
+ *
+ * @param string $payload Status response payload.
+ *
+ * @return string
+ */
+ public static function get($payload)
+ {
+ switch ($payload) {
+ case 'OK':
+ case 'QUEUED':
+ if (isset(self::$$payload)) {
+ return self::$$payload;
+ }
+
+ return self::$$payload = new self($payload);
+
+ default:
+ return new self($payload);
+ }
+ }
+}
diff --git a/vendor/predis/predis/src/Session/Handler.php b/vendor/predis/predis/src/Session/Handler.php
new file mode 100644
index 0000000..fee90ff
--- /dev/null
+++ b/vendor/predis/predis/src/Session/Handler.php
@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Session;
+
+use Predis\ClientInterface;
+
+/**
+ * Session handler class that relies on Predis\Client to store PHP's sessions
+ * data into one or multiple Redis servers.
+ *
+ * This class is mostly intended for PHP 5.4 but it can be used under PHP 5.3
+ * provided that a polyfill for `SessionHandlerInterface` is defined by either
+ * you or an external package such as `symfony/http-foundation`.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class Handler implements \SessionHandlerInterface
+{
+ protected $client;
+ protected $ttl;
+
+ /**
+ * @param ClientInterface $client Fully initialized client instance.
+ * @param array $options Session handler options.
+ */
+ public function __construct(ClientInterface $client, array $options = array())
+ {
+ $this->client = $client;
+
+ if (isset($options['gc_maxlifetime'])) {
+ $this->ttl = (int) $options['gc_maxlifetime'];
+ } else {
+ $this->ttl = ini_get('session.gc_maxlifetime');
+ }
+ }
+
+ /**
+ * Registers this instance as the current session handler.
+ */
+ public function register()
+ {
+ if (PHP_VERSION_ID >= 50400) {
+ session_set_save_handler($this, true);
+ } else {
+ session_set_save_handler(
+ array($this, 'open'),
+ array($this, 'close'),
+ array($this, 'read'),
+ array($this, 'write'),
+ array($this, 'destroy'),
+ array($this, 'gc')
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function open($save_path, $session_id)
+ {
+ // NOOP
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function close()
+ {
+ // NOOP
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function gc($maxlifetime)
+ {
+ // NOOP
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function read($session_id)
+ {
+ if ($data = $this->client->get($session_id)) {
+ return $data;
+ }
+
+ return '';
+ }
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function write($session_id, $session_data)
+ {
+ $this->client->setex($session_id, $this->ttl, $session_data);
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ #[\ReturnTypeWillChange]
+ public function destroy($session_id)
+ {
+ $this->client->del($session_id);
+
+ return true;
+ }
+
+ /**
+ * Returns the underlying client instance.
+ *
+ * @return ClientInterface
+ */
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ /**
+ * Returns the session max lifetime value.
+ *
+ * @return int
+ */
+ public function getMaxLifeTime()
+ {
+ return $this->ttl;
+ }
+}
diff --git a/vendor/predis/predis/src/Transaction/AbortedMultiExecException.php b/vendor/predis/predis/src/Transaction/AbortedMultiExecException.php
new file mode 100644
index 0000000..94499d8
--- /dev/null
+++ b/vendor/predis/predis/src/Transaction/AbortedMultiExecException.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Transaction;
+
+use Predis\PredisException;
+
+/**
+ * Exception class that identifies a MULTI / EXEC transaction aborted by Redis.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class AbortedMultiExecException extends PredisException
+{
+ private $transaction;
+
+ /**
+ * @param MultiExec $transaction Transaction that generated the exception.
+ * @param string $message Error message.
+ * @param int $code Error code.
+ */
+ public function __construct(MultiExec $transaction, $message, $code = null)
+ {
+ parent::__construct($message, is_null($code) ? 0 : $code);
+ $this->transaction = $transaction;
+ }
+
+ /**
+ * Returns the transaction that generated the exception.
+ *
+ * @return MultiExec
+ */
+ public function getTransaction()
+ {
+ return $this->transaction;
+ }
+}
diff --git a/vendor/predis/predis/src/Transaction/MultiExec.php b/vendor/predis/predis/src/Transaction/MultiExec.php
new file mode 100644
index 0000000..0cf1962
--- /dev/null
+++ b/vendor/predis/predis/src/Transaction/MultiExec.php
@@ -0,0 +1,461 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Transaction;
+
+use Predis\ClientContextInterface;
+use Predis\ClientException;
+use Predis\ClientInterface;
+use Predis\Command\CommandInterface;
+use Predis\CommunicationException;
+use Predis\Connection\AggregateConnectionInterface;
+use Predis\NotSupportedException;
+use Predis\Protocol\ProtocolException;
+use Predis\Response\ErrorInterface as ErrorResponseInterface;
+use Predis\Response\ServerException;
+use Predis\Response\Status as StatusResponse;
+
+/**
+ * Client-side abstraction of a Redis transaction based on MULTI / EXEC.
+ *
+ * {@inheritdoc}
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MultiExec implements ClientContextInterface
+{
+ private $state;
+
+ protected $client;
+ protected $commands;
+ protected $exceptions = true;
+ protected $attempts = 0;
+ protected $watchKeys = array();
+ protected $modeCAS = false;
+
+ /**
+ * @param ClientInterface $client Client instance used by the transaction.
+ * @param array $options Initialization options.
+ */
+ public function __construct(ClientInterface $client, array $options = null)
+ {
+ $this->assertClient($client);
+
+ $this->client = $client;
+ $this->state = new MultiExecState();
+
+ $this->configure($client, $options ?: array());
+ $this->reset();
+ }
+
+ /**
+ * Checks if the passed client instance satisfies the required conditions
+ * needed to initialize the transaction object.
+ *
+ * @param ClientInterface $client Client instance used by the transaction object.
+ *
+ * @throws NotSupportedException
+ */
+ private function assertClient(ClientInterface $client)
+ {
+ if ($client->getConnection() instanceof AggregateConnectionInterface) {
+ throw new NotSupportedException(
+ 'Cannot initialize a MULTI/EXEC transaction over aggregate connections.'
+ );
+ }
+
+ if (!$client->getProfile()->supportsCommands(array('MULTI', 'EXEC', 'DISCARD'))) {
+ throw new NotSupportedException(
+ 'The current profile does not support MULTI, EXEC and DISCARD.'
+ );
+ }
+ }
+
+ /**
+ * Configures the transaction using the provided options.
+ *
+ * @param ClientInterface $client Underlying client instance.
+ * @param array $options Array of options for the transaction.
+ **/
+ protected function configure(ClientInterface $client, array $options)
+ {
+ if (isset($options['exceptions'])) {
+ $this->exceptions = (bool) $options['exceptions'];
+ } else {
+ $this->exceptions = $client->getOptions()->exceptions;
+ }
+
+ if (isset($options['cas'])) {
+ $this->modeCAS = (bool) $options['cas'];
+ }
+
+ if (isset($options['watch']) && $keys = $options['watch']) {
+ $this->watchKeys = $keys;
+ }
+
+ if (isset($options['retry'])) {
+ $this->attempts = (int) $options['retry'];
+ }
+ }
+
+ /**
+ * Resets the state of the transaction.
+ */
+ protected function reset()
+ {
+ $this->state->reset();
+ $this->commands = new \SplQueue();
+ }
+
+ /**
+ * Initializes the transaction context.
+ */
+ protected function initialize()
+ {
+ if ($this->state->isInitialized()) {
+ return;
+ }
+
+ if ($this->modeCAS) {
+ $this->state->flag(MultiExecState::CAS);
+ }
+
+ if ($this->watchKeys) {
+ $this->watch($this->watchKeys);
+ }
+
+ $cas = $this->state->isCAS();
+ $discarded = $this->state->isDiscarded();
+
+ if (!$cas || ($cas && $discarded)) {
+ $this->call('MULTI');
+
+ if ($discarded) {
+ $this->state->unflag(MultiExecState::CAS);
+ }
+ }
+
+ $this->state->unflag(MultiExecState::DISCARDED);
+ $this->state->flag(MultiExecState::INITIALIZED);
+ }
+
+ /**
+ * Dynamically invokes a Redis command with the specified arguments.
+ *
+ * @param string $method Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @return mixed
+ */
+ public function __call($method, $arguments)
+ {
+ return $this->executeCommand(
+ $this->client->createCommand($method, $arguments)
+ );
+ }
+
+ /**
+ * Executes a Redis command bypassing the transaction logic.
+ *
+ * @param string $commandID Command ID.
+ * @param array $arguments Arguments for the command.
+ *
+ * @throws ServerException
+ *
+ * @return mixed
+ */
+ protected function call($commandID, array $arguments = array())
+ {
+ $response = $this->client->executeCommand(
+ $this->client->createCommand($commandID, $arguments)
+ );
+
+ if ($response instanceof ErrorResponseInterface) {
+ throw new ServerException($response->getMessage());
+ }
+
+ return $response;
+ }
+
+ /**
+ * Executes the specified Redis command.
+ *
+ * @param CommandInterface $command Command instance.
+ *
+ * @throws AbortedMultiExecException
+ * @throws CommunicationException
+ *
+ * @return $this|mixed
+ */
+ public function executeCommand(CommandInterface $command)
+ {
+ $this->initialize();
+
+ if ($this->state->isCAS()) {
+ return $this->client->executeCommand($command);
+ }
+
+ $response = $this->client->getConnection()->executeCommand($command);
+
+ if ($response instanceof StatusResponse && $response == 'QUEUED') {
+ $this->commands->enqueue($command);
+ } elseif ($response instanceof ErrorResponseInterface) {
+ throw new AbortedMultiExecException($this, $response->getMessage());
+ } else {
+ $this->onProtocolError('The server did not return a +QUEUED status response.');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Executes WATCH against one or more keys.
+ *
+ * @param string|array $keys One or more keys.
+ *
+ * @throws NotSupportedException
+ * @throws ClientException
+ *
+ * @return mixed
+ */
+ public function watch($keys)
+ {
+ if (!$this->client->getProfile()->supportsCommand('WATCH')) {
+ throw new NotSupportedException('WATCH is not supported by the current profile.');
+ }
+
+ if ($this->state->isWatchAllowed()) {
+ throw new ClientException('Sending WATCH after MULTI is not allowed.');
+ }
+
+ $response = $this->call('WATCH', is_array($keys) ? $keys : array($keys));
+ $this->state->flag(MultiExecState::WATCH);
+
+ return $response;
+ }
+
+ /**
+ * Finalizes the transaction by executing MULTI on the server.
+ *
+ * @return MultiExec
+ */
+ public function multi()
+ {
+ if ($this->state->check(MultiExecState::INITIALIZED | MultiExecState::CAS)) {
+ $this->state->unflag(MultiExecState::CAS);
+ $this->call('MULTI');
+ } else {
+ $this->initialize();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Executes UNWATCH.
+ *
+ * @throws NotSupportedException
+ *
+ * @return MultiExec
+ */
+ public function unwatch()
+ {
+ if (!$this->client->getProfile()->supportsCommand('UNWATCH')) {
+ throw new NotSupportedException(
+ 'UNWATCH is not supported by the current profile.'
+ );
+ }
+
+ $this->state->unflag(MultiExecState::WATCH);
+ $this->__call('UNWATCH', array());
+
+ return $this;
+ }
+
+ /**
+ * Resets the transaction by UNWATCH-ing the keys that are being WATCHed and
+ * DISCARD-ing pending commands that have been already sent to the server.
+ *
+ * @return MultiExec
+ */
+ public function discard()
+ {
+ if ($this->state->isInitialized()) {
+ $this->call($this->state->isCAS() ? 'UNWATCH' : 'DISCARD');
+
+ $this->reset();
+ $this->state->flag(MultiExecState::DISCARDED);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Executes the whole transaction.
+ *
+ * @return mixed
+ */
+ public function exec()
+ {
+ return $this->execute();
+ }
+
+ /**
+ * Checks the state of the transaction before execution.
+ *
+ * @param mixed $callable Callback for execution.
+ *
+ * @throws \InvalidArgumentException
+ * @throws ClientException
+ */
+ private function checkBeforeExecution($callable)
+ {
+ if ($this->state->isExecuting()) {
+ throw new ClientException(
+ 'Cannot invoke "execute" or "exec" inside an active transaction context.'
+ );
+ }
+
+ if ($callable) {
+ if (!is_callable($callable)) {
+ throw new \InvalidArgumentException('The argument must be a callable object.');
+ }
+
+ if (!$this->commands->isEmpty()) {
+ $this->discard();
+
+ throw new ClientException(
+ 'Cannot execute a transaction block after using fluent interface.'
+ );
+ }
+ } elseif ($this->attempts) {
+ $this->discard();
+
+ throw new ClientException(
+ 'Automatic retries are supported only when a callable block is provided.'
+ );
+ }
+ }
+
+ /**
+ * Handles the actual execution of the whole transaction.
+ *
+ * @param mixed $callable Optional callback for execution.
+ *
+ * @throws CommunicationException
+ * @throws AbortedMultiExecException
+ * @throws ServerException
+ *
+ * @return array
+ */
+ public function execute($callable = null)
+ {
+ $this->checkBeforeExecution($callable);
+
+ $execResponse = null;
+ $attempts = $this->attempts;
+
+ do {
+ if ($callable) {
+ $this->executeTransactionBlock($callable);
+ }
+
+ if ($this->commands->isEmpty()) {
+ if ($this->state->isWatching()) {
+ $this->discard();
+ }
+
+ return;
+ }
+
+ $execResponse = $this->call('EXEC');
+
+ if ($execResponse === null) {
+ if ($attempts === 0) {
+ throw new AbortedMultiExecException(
+ $this, 'The current transaction has been aborted by the server.'
+ );
+ }
+
+ $this->reset();
+
+ continue;
+ }
+
+ break;
+ } while ($attempts-- > 0);
+
+ $response = array();
+ $commands = $this->commands;
+ $size = count($execResponse);
+
+ if ($size !== count($commands)) {
+ $this->onProtocolError('EXEC returned an unexpected number of response items.');
+ }
+
+ for ($i = 0; $i < $size; ++$i) {
+ $cmdResponse = $execResponse[$i];
+
+ if ($cmdResponse instanceof ErrorResponseInterface && $this->exceptions) {
+ throw new ServerException($cmdResponse->getMessage());
+ }
+
+ $response[$i] = $commands->dequeue()->parseResponse($cmdResponse);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Passes the current transaction object to a callable block for execution.
+ *
+ * @param mixed $callable Callback.
+ *
+ * @throws CommunicationException
+ * @throws ServerException
+ */
+ protected function executeTransactionBlock($callable)
+ {
+ $exception = null;
+ $this->state->flag(MultiExecState::INSIDEBLOCK);
+
+ try {
+ call_user_func($callable, $this);
+ } catch (CommunicationException $exception) {
+ // NOOP
+ } catch (ServerException $exception) {
+ // NOOP
+ } catch (\Exception $exception) {
+ $this->discard();
+ }
+
+ $this->state->unflag(MultiExecState::INSIDEBLOCK);
+
+ if ($exception) {
+ throw $exception;
+ }
+ }
+
+ /**
+ * Helper method for protocol errors encountered inside the transaction.
+ *
+ * @param string $message Error message.
+ */
+ private function onProtocolError($message)
+ {
+ // Since a MULTI/EXEC block cannot be initialized when using aggregate
+ // connections we can safely assume that Predis\Client::getConnection()
+ // will return a Predis\Connection\NodeConnectionInterface instance.
+ CommunicationException::handle(new ProtocolException(
+ $this->client->getConnection(), $message
+ ));
+ }
+}
diff --git a/vendor/predis/predis/src/Transaction/MultiExecState.php b/vendor/predis/predis/src/Transaction/MultiExecState.php
new file mode 100644
index 0000000..4bed42a
--- /dev/null
+++ b/vendor/predis/predis/src/Transaction/MultiExecState.php
@@ -0,0 +1,166 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Transaction;
+
+/**
+ * Utility class used to track the state of a MULTI / EXEC transaction.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class MultiExecState
+{
+ const INITIALIZED = 1; // 0b00001
+ const INSIDEBLOCK = 2; // 0b00010
+ const DISCARDED = 4; // 0b00100
+ const CAS = 8; // 0b01000
+ const WATCH = 16; // 0b10000
+
+ private $flags;
+
+ /**
+ *
+ */
+ public function __construct()
+ {
+ $this->flags = 0;
+ }
+
+ /**
+ * Sets the internal state flags.
+ *
+ * @param int $flags Set of flags
+ */
+ public function set($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /**
+ * Gets the internal state flags.
+ *
+ * @return int
+ */
+ public function get()
+ {
+ return $this->flags;
+ }
+
+ /**
+ * Sets one or more flags.
+ *
+ * @param int $flags Set of flags
+ */
+ public function flag($flags)
+ {
+ $this->flags |= $flags;
+ }
+
+ /**
+ * Resets one or more flags.
+ *
+ * @param int $flags Set of flags
+ */
+ public function unflag($flags)
+ {
+ $this->flags &= ~$flags;
+ }
+
+ /**
+ * Returns if the specified flag or set of flags is set.
+ *
+ * @param int $flags Flag
+ *
+ * @return bool
+ */
+ public function check($flags)
+ {
+ return ($this->flags & $flags) === $flags;
+ }
+
+ /**
+ * Resets the state of a transaction.
+ */
+ public function reset()
+ {
+ $this->flags = 0;
+ }
+
+ /**
+ * Returns the state of the RESET flag.
+ *
+ * @return bool
+ */
+ public function isReset()
+ {
+ return $this->flags === 0;
+ }
+
+ /**
+ * Returns the state of the INITIALIZED flag.
+ *
+ * @return bool
+ */
+ public function isInitialized()
+ {
+ return $this->check(self::INITIALIZED);
+ }
+
+ /**
+ * Returns the state of the INSIDEBLOCK flag.
+ *
+ * @return bool
+ */
+ public function isExecuting()
+ {
+ return $this->check(self::INSIDEBLOCK);
+ }
+
+ /**
+ * Returns the state of the CAS flag.
+ *
+ * @return bool
+ */
+ public function isCAS()
+ {
+ return $this->check(self::CAS);
+ }
+
+ /**
+ * Returns if WATCH is allowed in the current state.
+ *
+ * @return bool
+ */
+ public function isWatchAllowed()
+ {
+ return $this->check(self::INITIALIZED) && !$this->check(self::CAS);
+ }
+
+ /**
+ * Returns the state of the WATCH flag.
+ *
+ * @return bool
+ */
+ public function isWatching()
+ {
+ return $this->check(self::WATCH);
+ }
+
+ /**
+ * Returns the state of the DISCARDED flag.
+ *
+ * @return bool
+ */
+ public function isDiscarded()
+ {
+ return $this->check(self::DISCARDED);
+ }
+}
diff --git a/vendor/psr/http-message/LICENSE b/vendor/psr/http-message/LICENSE
new file mode 100644
index 0000000..c2d8e45
--- /dev/null
+++ b/vendor/psr/http-message/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 PHP Framework Interoperability Group
+
+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/psr/http-message/composer.json b/vendor/psr/http-message/composer.json
new file mode 100644
index 0000000..b0d2937
--- /dev/null
+++ b/vendor/psr/http-message/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "psr/http-message",
+ "description": "Common interface for HTTP messages",
+ "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
+ "homepage": "https://github.com/php-fig/http-message",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ }
+}
diff --git a/vendor/psr/http-message/src/MessageInterface.php b/vendor/psr/http-message/src/MessageInterface.php
new file mode 100644
index 0000000..dd46e5e
--- /dev/null
+++ b/vendor/psr/http-message/src/MessageInterface.php
@@ -0,0 +1,187 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * HTTP messages consist of requests from a client to a server and responses
+ * from a server to a client. This interface defines the methods common to
+ * each.
+ *
+ * Messages are considered immutable; all methods that might change state MUST
+ * be implemented such that they retain the internal state of the current
+ * message and return an instance that contains the changed state.
+ *
+ * @link http://www.ietf.org/rfc/rfc7230.txt
+ * @link http://www.ietf.org/rfc/rfc7231.txt
+ */
+interface MessageInterface
+{
+ /**
+ * Retrieves the HTTP protocol version as a string.
+ *
+ * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
+ *
+ * @return string HTTP protocol version.
+ */
+ public function getProtocolVersion();
+
+ /**
+ * Return an instance with the specified HTTP protocol version.
+ *
+ * The version string MUST contain only the HTTP version number (e.g.,
+ * "1.1", "1.0").
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new protocol version.
+ *
+ * @param string $version HTTP protocol version
+ * @return static
+ */
+ public function withProtocolVersion($version);
+
+ /**
+ * Retrieves all message header values.
+ *
+ * The keys represent the header name as it will be sent over the wire, and
+ * each value is an array of strings associated with the header.
+ *
+ * // Represent the headers as a string
+ * foreach ($message->getHeaders() as $name => $values) {
+ * echo $name . ": " . implode(", ", $values);
+ * }
+ *
+ * // Emit headers iteratively:
+ * foreach ($message->getHeaders() as $name => $values) {
+ * foreach ($values as $value) {
+ * header(sprintf('%s: %s', $name, $value), false);
+ * }
+ * }
+ *
+ * While header names are not case-sensitive, getHeaders() will preserve the
+ * exact case in which headers were originally specified.
+ *
+ * @return string[][] Returns an associative array of the message's headers. Each
+ * key MUST be a header name, and each value MUST be an array of strings
+ * for that header.
+ */
+ public function getHeaders();
+
+ /**
+ * Checks if a header exists by the given case-insensitive name.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return bool Returns true if any header names match the given header
+ * name using a case-insensitive string comparison. Returns false if
+ * no matching header name is found in the message.
+ */
+ public function hasHeader($name);
+
+ /**
+ * Retrieves a message header value by the given case-insensitive name.
+ *
+ * This method returns an array of all the header values of the given
+ * case-insensitive header name.
+ *
+ * If the header does not appear in the message, this method MUST return an
+ * empty array.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string[] An array of string values as provided for the given
+ * header. If the header does not appear in the message, this method MUST
+ * return an empty array.
+ */
+ public function getHeader($name);
+
+ /**
+ * Retrieves a comma-separated string of the values for a single header.
+ *
+ * This method returns all of the header values of the given
+ * case-insensitive header name as a string concatenated together using
+ * a comma.
+ *
+ * NOTE: Not all header values may be appropriately represented using
+ * comma concatenation. For such headers, use getHeader() instead
+ * and supply your own delimiter when concatenating.
+ *
+ * If the header does not appear in the message, this method MUST return
+ * an empty string.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string A string of values as provided for the given header
+ * concatenated together using a comma. If the header does not appear in
+ * the message, this method MUST return an empty string.
+ */
+ public function getHeaderLine($name);
+
+ /**
+ * Return an instance with the provided value replacing the specified header.
+ *
+ * While header names are case-insensitive, the casing of the header will
+ * be preserved by this function, and returned from getHeaders().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new and/or updated header and value.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withHeader($name, $value);
+
+ /**
+ * Return an instance with the specified header appended with the given value.
+ *
+ * Existing values for the specified header will be maintained. The new
+ * value(s) will be appended to the existing list. If the header did not
+ * exist previously, it will be added.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new header and/or value.
+ *
+ * @param string $name Case-insensitive header field name to add.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withAddedHeader($name, $value);
+
+ /**
+ * Return an instance without the specified header.
+ *
+ * Header resolution MUST be done without case-sensitivity.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the named header.
+ *
+ * @param string $name Case-insensitive header field name to remove.
+ * @return static
+ */
+ public function withoutHeader($name);
+
+ /**
+ * Gets the body of the message.
+ *
+ * @return StreamInterface Returns the body as a stream.
+ */
+ public function getBody();
+
+ /**
+ * Return an instance with the specified message body.
+ *
+ * The body MUST be a StreamInterface object.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return a new instance that has the
+ * new body stream.
+ *
+ * @param StreamInterface $body Body.
+ * @return static
+ * @throws \InvalidArgumentException When the body is not valid.
+ */
+ public function withBody(StreamInterface $body);
+}
diff --git a/vendor/psr/http-message/src/RequestInterface.php b/vendor/psr/http-message/src/RequestInterface.php
new file mode 100644
index 0000000..a96d4fd
--- /dev/null
+++ b/vendor/psr/http-message/src/RequestInterface.php
@@ -0,0 +1,129 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * Representation of an outgoing, client-side request.
+ *
+ * Per the HTTP specification, this interface includes properties for
+ * each of the following:
+ *
+ * - Protocol version
+ * - HTTP method
+ * - URI
+ * - Headers
+ * - Message body
+ *
+ * During construction, implementations MUST attempt to set the Host header from
+ * a provided URI if no Host header is provided.
+ *
+ * Requests are considered immutable; all methods that might change state MUST
+ * be implemented such that they retain the internal state of the current
+ * message and return an instance that contains the changed state.
+ */
+interface RequestInterface extends MessageInterface
+{
+ /**
+ * Retrieves the message's request target.
+ *
+ * Retrieves the message's request-target either as it will appear (for
+ * clients), as it appeared at request (for servers), or as it was
+ * specified for the instance (see withRequestTarget()).
+ *
+ * In most cases, this will be the origin-form of the composed URI,
+ * unless a value was provided to the concrete implementation (see
+ * withRequestTarget() below).
+ *
+ * If no URI is available, and no request-target has been specifically
+ * provided, this method MUST return the string "/".
+ *
+ * @return string
+ */
+ public function getRequestTarget();
+
+ /**
+ * Return an instance with the specific request-target.
+ *
+ * If the request needs a non-origin-form request-target — e.g., for
+ * specifying an absolute-form, authority-form, or asterisk-form —
+ * this method may be used to create an instance with the specified
+ * request-target, verbatim.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * changed request target.
+ *
+ * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
+ * request-target forms allowed in request messages)
+ * @param mixed $requestTarget
+ * @return static
+ */
+ public function withRequestTarget($requestTarget);
+
+ /**
+ * Retrieves the HTTP method of the request.
+ *
+ * @return string Returns the request method.
+ */
+ public function getMethod();
+
+ /**
+ * Return an instance with the provided HTTP method.
+ *
+ * While HTTP method names are typically all uppercase characters, HTTP
+ * method names are case-sensitive and thus implementations SHOULD NOT
+ * modify the given string.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * changed request method.
+ *
+ * @param string $method Case-sensitive method.
+ * @return static
+ * @throws \InvalidArgumentException for invalid HTTP methods.
+ */
+ public function withMethod($method);
+
+ /**
+ * Retrieves the URI instance.
+ *
+ * This method MUST return a UriInterface instance.
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-4.3
+ * @return UriInterface Returns a UriInterface instance
+ * representing the URI of the request.
+ */
+ public function getUri();
+
+ /**
+ * Returns an instance with the provided URI.
+ *
+ * This method MUST update the Host header of the returned request by
+ * default if the URI contains a host component. If the URI does not
+ * contain a host component, any pre-existing Host header MUST be carried
+ * over to the returned request.
+ *
+ * You can opt-in to preserving the original state of the Host header by
+ * setting `$preserveHost` to `true`. When `$preserveHost` is set to
+ * `true`, this method interacts with the Host header in the following ways:
+ *
+ * - If the Host header is missing or empty, and the new URI contains
+ * a host component, this method MUST update the Host header in the returned
+ * request.
+ * - If the Host header is missing or empty, and the new URI does not contain a
+ * host component, this method MUST NOT update the Host header in the returned
+ * request.
+ * - If a Host header is present and non-empty, this method MUST NOT update
+ * the Host header in the returned request.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new UriInterface instance.
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-4.3
+ * @param UriInterface $uri New request URI to use.
+ * @param bool $preserveHost Preserve the original state of the Host header.
+ * @return static
+ */
+ public function withUri(UriInterface $uri, $preserveHost = false);
+}
diff --git a/vendor/psr/http-message/src/ResponseInterface.php b/vendor/psr/http-message/src/ResponseInterface.php
new file mode 100644
index 0000000..c306514
--- /dev/null
+++ b/vendor/psr/http-message/src/ResponseInterface.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * Representation of an outgoing, server-side response.
+ *
+ * Per the HTTP specification, this interface includes properties for
+ * each of the following:
+ *
+ * - Protocol version
+ * - Status code and reason phrase
+ * - Headers
+ * - Message body
+ *
+ * Responses are considered immutable; all methods that might change state MUST
+ * be implemented such that they retain the internal state of the current
+ * message and return an instance that contains the changed state.
+ */
+interface ResponseInterface extends MessageInterface
+{
+ /**
+ * Gets the response status code.
+ *
+ * The status code is a 3-digit integer result code of the server's attempt
+ * to understand and satisfy the request.
+ *
+ * @return int Status code.
+ */
+ public function getStatusCode();
+
+ /**
+ * Return an instance with the specified status code and, optionally, reason phrase.
+ *
+ * If no reason phrase is specified, implementations MAY choose to default
+ * to the RFC 7231 or IANA recommended reason phrase for the response's
+ * status code.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated status and reason phrase.
+ *
+ * @link http://tools.ietf.org/html/rfc7231#section-6
+ * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
+ * @param int $code The 3-digit integer result code to set.
+ * @param string $reasonPhrase The reason phrase to use with the
+ * provided status code; if none is provided, implementations MAY
+ * use the defaults as suggested in the HTTP specification.
+ * @return static
+ * @throws \InvalidArgumentException For invalid status code arguments.
+ */
+ public function withStatus($code, $reasonPhrase = '');
+
+ /**
+ * Gets the response reason phrase associated with the status code.
+ *
+ * Because a reason phrase is not a required element in a response
+ * status line, the reason phrase value MAY be null. Implementations MAY
+ * choose to return the default RFC 7231 recommended reason phrase (or those
+ * listed in the IANA HTTP Status Code Registry) for the response's
+ * status code.
+ *
+ * @link http://tools.ietf.org/html/rfc7231#section-6
+ * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
+ * @return string Reason phrase; must return an empty string if none present.
+ */
+ public function getReasonPhrase();
+}
diff --git a/vendor/psr/http-message/src/ServerRequestInterface.php b/vendor/psr/http-message/src/ServerRequestInterface.php
new file mode 100644
index 0000000..0251234
--- /dev/null
+++ b/vendor/psr/http-message/src/ServerRequestInterface.php
@@ -0,0 +1,261 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * Representation of an incoming, server-side HTTP request.
+ *
+ * Per the HTTP specification, this interface includes properties for
+ * each of the following:
+ *
+ * - Protocol version
+ * - HTTP method
+ * - URI
+ * - Headers
+ * - Message body
+ *
+ * Additionally, it encapsulates all data as it has arrived to the
+ * application from the CGI and/or PHP environment, including:
+ *
+ * - The values represented in $_SERVER.
+ * - Any cookies provided (generally via $_COOKIE)
+ * - Query string arguments (generally via $_GET, or as parsed via parse_str())
+ * - Upload files, if any (as represented by $_FILES)
+ * - Deserialized body parameters (generally from $_POST)
+ *
+ * $_SERVER values MUST be treated as immutable, as they represent application
+ * state at the time of request; as such, no methods are provided to allow
+ * modification of those values. The other values provide such methods, as they
+ * can be restored from $_SERVER or the request body, and may need treatment
+ * during the application (e.g., body parameters may be deserialized based on
+ * content type).
+ *
+ * Additionally, this interface recognizes the utility of introspecting a
+ * request to derive and match additional parameters (e.g., via URI path
+ * matching, decrypting cookie values, deserializing non-form-encoded body
+ * content, matching authorization headers to users, etc). These parameters
+ * are stored in an "attributes" property.
+ *
+ * Requests are considered immutable; all methods that might change state MUST
+ * be implemented such that they retain the internal state of the current
+ * message and return an instance that contains the changed state.
+ */
+interface ServerRequestInterface extends RequestInterface
+{
+ /**
+ * Retrieve server parameters.
+ *
+ * Retrieves data related to the incoming request environment,
+ * typically derived from PHP's $_SERVER superglobal. The data IS NOT
+ * REQUIRED to originate from $_SERVER.
+ *
+ * @return array
+ */
+ public function getServerParams();
+
+ /**
+ * Retrieve cookies.
+ *
+ * Retrieves cookies sent by the client to the server.
+ *
+ * The data MUST be compatible with the structure of the $_COOKIE
+ * superglobal.
+ *
+ * @return array
+ */
+ public function getCookieParams();
+
+ /**
+ * Return an instance with the specified cookies.
+ *
+ * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST
+ * be compatible with the structure of $_COOKIE. Typically, this data will
+ * be injected at instantiation.
+ *
+ * This method MUST NOT update the related Cookie header of the request
+ * instance, nor related values in the server params.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated cookie values.
+ *
+ * @param array $cookies Array of key/value pairs representing cookies.
+ * @return static
+ */
+ public function withCookieParams(array $cookies);
+
+ /**
+ * Retrieve query string arguments.
+ *
+ * Retrieves the deserialized query string arguments, if any.
+ *
+ * Note: the query params might not be in sync with the URI or server
+ * params. If you need to ensure you are only getting the original
+ * values, you may need to parse the query string from `getUri()->getQuery()`
+ * or from the `QUERY_STRING` server param.
+ *
+ * @return array
+ */
+ public function getQueryParams();
+
+ /**
+ * Return an instance with the specified query string arguments.
+ *
+ * These values SHOULD remain immutable over the course of the incoming
+ * request. They MAY be injected during instantiation, such as from PHP's
+ * $_GET superglobal, or MAY be derived from some other value such as the
+ * URI. In cases where the arguments are parsed from the URI, the data
+ * MUST be compatible with what PHP's parse_str() would return for
+ * purposes of how duplicate query parameters are handled, and how nested
+ * sets are handled.
+ *
+ * Setting query string arguments MUST NOT change the URI stored by the
+ * request, nor the values in the server params.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated query string arguments.
+ *
+ * @param array $query Array of query string arguments, typically from
+ * $_GET.
+ * @return static
+ */
+ public function withQueryParams(array $query);
+
+ /**
+ * Retrieve normalized file upload data.
+ *
+ * This method returns upload metadata in a normalized tree, with each leaf
+ * an instance of Psr\Http\Message\UploadedFileInterface.
+ *
+ * These values MAY be prepared from $_FILES or the message body during
+ * instantiation, or MAY be injected via withUploadedFiles().
+ *
+ * @return array An array tree of UploadedFileInterface instances; an empty
+ * array MUST be returned if no data is present.
+ */
+ public function getUploadedFiles();
+
+ /**
+ * Create a new instance with the specified uploaded files.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
+ * @return static
+ * @throws \InvalidArgumentException if an invalid structure is provided.
+ */
+ public function withUploadedFiles(array $uploadedFiles);
+
+ /**
+ * Retrieve any parameters provided in the request body.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, this method MUST
+ * return the contents of $_POST.
+ *
+ * Otherwise, this method may return any results of deserializing
+ * the request body content; as parsing returns structured content, the
+ * potential types MUST be arrays or objects only. A null value indicates
+ * the absence of body content.
+ *
+ * @return null|array|object The deserialized body parameters, if any.
+ * These will typically be an array or object.
+ */
+ public function getParsedBody();
+
+ /**
+ * Return an instance with the specified body parameters.
+ *
+ * These MAY be injected during instantiation.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, use this method
+ * ONLY to inject the contents of $_POST.
+ *
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
+ * deserializing the request body content. Deserialization/parsing returns
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
+ * or a null value if nothing was available to parse.
+ *
+ * As an example, if content negotiation determines that the request data
+ * is a JSON payload, this method could be used to create a request
+ * instance with the deserialized parameters.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param null|array|object $data The deserialized body data. This will
+ * typically be in an array or object.
+ * @return static
+ * @throws \InvalidArgumentException if an unsupported argument type is
+ * provided.
+ */
+ public function withParsedBody($data);
+
+ /**
+ * Retrieve attributes derived from the request.
+ *
+ * The request "attributes" may be used to allow injection of any
+ * parameters derived from the request: e.g., the results of path
+ * match operations; the results of decrypting cookies; the results of
+ * deserializing non-form-encoded message bodies; etc. Attributes
+ * will be application and request specific, and CAN be mutable.
+ *
+ * @return array Attributes derived from the request.
+ */
+ public function getAttributes();
+
+ /**
+ * Retrieve a single derived request attribute.
+ *
+ * Retrieves a single derived request attribute as described in
+ * getAttributes(). If the attribute has not been previously set, returns
+ * the default value as provided.
+ *
+ * This method obviates the need for a hasAttribute() method, as it allows
+ * specifying a default value to return if the attribute is not found.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $default Default value to return if the attribute does not exist.
+ * @return mixed
+ */
+ public function getAttribute($name, $default = null);
+
+ /**
+ * Return an instance with the specified derived request attribute.
+ *
+ * This method allows setting a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $value The value of the attribute.
+ * @return static
+ */
+ public function withAttribute($name, $value);
+
+ /**
+ * Return an instance that removes the specified derived request attribute.
+ *
+ * This method allows removing a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @return static
+ */
+ public function withoutAttribute($name);
+}
diff --git a/vendor/psr/http-message/src/StreamInterface.php b/vendor/psr/http-message/src/StreamInterface.php
new file mode 100644
index 0000000..f68f391
--- /dev/null
+++ b/vendor/psr/http-message/src/StreamInterface.php
@@ -0,0 +1,158 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * Describes a data stream.
+ *
+ * Typically, an instance will wrap a PHP stream; this interface provides
+ * a wrapper around the most common operations, including serialization of
+ * the entire stream to a string.
+ */
+interface StreamInterface
+{
+ /**
+ * Reads all data from the stream into a string, from the beginning to end.
+ *
+ * This method MUST attempt to seek to the beginning of the stream before
+ * reading data and read the stream until the end is reached.
+ *
+ * Warning: This could attempt to load a large amount of data into memory.
+ *
+ * This method MUST NOT raise an exception in order to conform with PHP's
+ * string casting operations.
+ *
+ * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Closes the stream and any underlying resources.
+ *
+ * @return void
+ */
+ public function close();
+
+ /**
+ * Separates any underlying resources from the stream.
+ *
+ * After the stream has been detached, the stream is in an unusable state.
+ *
+ * @return resource|null Underlying PHP stream, if any
+ */
+ public function detach();
+
+ /**
+ * Get the size of the stream if known.
+ *
+ * @return int|null Returns the size in bytes if known, or null if unknown.
+ */
+ public function getSize();
+
+ /**
+ * Returns the current position of the file read/write pointer
+ *
+ * @return int Position of the file pointer
+ * @throws \RuntimeException on error.
+ */
+ public function tell();
+
+ /**
+ * Returns true if the stream is at the end of the stream.
+ *
+ * @return bool
+ */
+ public function eof();
+
+ /**
+ * Returns whether or not the stream is seekable.
+ *
+ * @return bool
+ */
+ public function isSeekable();
+
+ /**
+ * Seek to a position in the stream.
+ *
+ * @link http://www.php.net/manual/en/function.fseek.php
+ * @param int $offset Stream offset
+ * @param int $whence Specifies how the cursor position will be calculated
+ * based on the seek offset. Valid values are identical to the built-in
+ * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
+ * offset bytes SEEK_CUR: Set position to current location plus offset
+ * SEEK_END: Set position to end-of-stream plus offset.
+ * @throws \RuntimeException on failure.
+ */
+ public function seek($offset, $whence = SEEK_SET);
+
+ /**
+ * Seek to the beginning of the stream.
+ *
+ * If the stream is not seekable, this method will raise an exception;
+ * otherwise, it will perform a seek(0).
+ *
+ * @see seek()
+ * @link http://www.php.net/manual/en/function.fseek.php
+ * @throws \RuntimeException on failure.
+ */
+ public function rewind();
+
+ /**
+ * Returns whether or not the stream is writable.
+ *
+ * @return bool
+ */
+ public function isWritable();
+
+ /**
+ * Write data to the stream.
+ *
+ * @param string $string The string that is to be written.
+ * @return int Returns the number of bytes written to the stream.
+ * @throws \RuntimeException on failure.
+ */
+ public function write($string);
+
+ /**
+ * Returns whether or not the stream is readable.
+ *
+ * @return bool
+ */
+ public function isReadable();
+
+ /**
+ * Read data from the stream.
+ *
+ * @param int $length Read up to $length bytes from the object and return
+ * them. Fewer than $length bytes may be returned if underlying stream
+ * call returns fewer bytes.
+ * @return string Returns the data read from the stream, or an empty string
+ * if no bytes are available.
+ * @throws \RuntimeException if an error occurs.
+ */
+ public function read($length);
+
+ /**
+ * Returns the remaining contents in a string
+ *
+ * @return string
+ * @throws \RuntimeException if unable to read or an error occurs while
+ * reading.
+ */
+ public function getContents();
+
+ /**
+ * Get stream metadata as an associative array or retrieve a specific key.
+ *
+ * The keys returned are identical to the keys returned from PHP's
+ * stream_get_meta_data() function.
+ *
+ * @link http://php.net/manual/en/function.stream-get-meta-data.php
+ * @param string $key Specific metadata to retrieve.
+ * @return array|mixed|null Returns an associative array if no key is
+ * provided. Returns a specific key value if a key is provided and the
+ * value is found, or null if the key is not found.
+ */
+ public function getMetadata($key = null);
+}
diff --git a/vendor/psr/http-message/src/UploadedFileInterface.php b/vendor/psr/http-message/src/UploadedFileInterface.php
new file mode 100644
index 0000000..f8a6901
--- /dev/null
+++ b/vendor/psr/http-message/src/UploadedFileInterface.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace Psr\Http\Message;
+
+/**
+ * Value object representing a file uploaded through an HTTP request.
+ *
+ * Instances of this interface are considered immutable; all methods that
+ * might change state MUST be implemented such that they retain the internal
+ * state of the current instance and return an instance that contains the
+ * changed state.
+ */
+interface UploadedFileInterface
+{
+ /**
+ * Retrieve a stream representing the uploaded file.
+ *
+ * This method MUST return a StreamInterface instance, representing the
+ * uploaded file. The purpose of this method is to allow utilizing native PHP
+ * stream functionality to manipulate the file upload, such as
+ * stream_copy_to_stream() (though the result will need to be decorated in a
+ * native PHP stream wrapper to work with such functions).
+ *
+ * If the moveTo() method has been called previously, this method MUST raise
+ * an exception.
+ *
+ * @return StreamInterface Stream representation of the uploaded file.
+ * @throws \RuntimeException in cases when no stream is available or can be
+ * created.
+ */
+ public function getStream();
+
+ /**
+ * Move the uploaded file to a new location.
+ *
+ * Use this method as an alternative to move_uploaded_file(). This method is
+ * guaranteed to work in both SAPI and non-SAPI environments.
+ * Implementations must determine which environment they are in, and use the
+ * appropriate method (move_uploaded_file(), rename(), or a stream
+ * operation) to perform the operation.
+ *
+ * $targetPath may be an absolute path, or a relative path. If it is a
+ * relative path, resolution should be the same as used by PHP's rename()
+ * function.
+ *
+ * The original file or stream MUST be removed on completion.
+ *
+ * If this method is called more than once, any subsequent calls MUST raise
+ * an exception.
+ *
+ * When used in an SAPI environment where $_FILES is populated, when writing
+ * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
+ * used to ensure permissions and upload status are verified correctly.
+ *
+ * If you wish to move to a stream, use getStream(), as SAPI operations
+ * cannot guarantee writing to stream destinations.
+ *
+ * @see http://php.net/is_uploaded_file
+ * @see http://php.net/move_uploaded_file
+ * @param string $targetPath Path to which to move the uploaded file.
+ * @throws \InvalidArgumentException if the $targetPath specified is invalid.
+ * @throws \RuntimeException on any error during the move operation, or on
+ * the second or subsequent call to the method.
+ */
+ public function moveTo($targetPath);
+
+ /**
+ * Retrieve the file size.
+ *
+ * Implementations SHOULD return the value stored in the "size" key of
+ * the file in the $_FILES array if available, as PHP calculates this based
+ * on the actual size transmitted.
+ *
+ * @return int|null The file size in bytes or null if unknown.
+ */
+ public function getSize();
+
+ /**
+ * Retrieve the error associated with the uploaded file.
+ *
+ * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.
+ *
+ * If the file was uploaded successfully, this method MUST return
+ * UPLOAD_ERR_OK.
+ *
+ * Implementations SHOULD return the value stored in the "error" key of
+ * the file in the $_FILES array.
+ *
+ * @see http://php.net/manual/en/features.file-upload.errors.php
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
+ */
+ public function getError();
+
+ /**
+ * Retrieve the filename sent by the client.
+ *
+ * Do not trust the value returned by this method. A client could send
+ * a malicious filename with the intention to corrupt or hack your
+ * application.
+ *
+ * Implementations SHOULD return the value stored in the "name" key of
+ * the file in the $_FILES array.
+ *
+ * @return string|null The filename sent by the client or null if none
+ * was provided.
+ */
+ public function getClientFilename();
+
+ /**
+ * Retrieve the media type sent by the client.
+ *
+ * Do not trust the value returned by this method. A client could send
+ * a malicious media type with the intention to corrupt or hack your
+ * application.
+ *
+ * Implementations SHOULD return the value stored in the "type" key of
+ * the file in the $_FILES array.
+ *
+ * @return string|null The media type sent by the client or null if none
+ * was provided.
+ */
+ public function getClientMediaType();
+}
diff --git a/vendor/psr/http-message/src/UriInterface.php b/vendor/psr/http-message/src/UriInterface.php
new file mode 100644
index 0000000..9d7ab9e
--- /dev/null
+++ b/vendor/psr/http-message/src/UriInterface.php
@@ -0,0 +1,323 @@
+<?php
+namespace Psr\Http\Message;
+
+/**
+ * Value object representing a URI.
+ *
+ * This interface is meant to represent URIs according to RFC 3986 and to
+ * provide methods for most common operations. Additional functionality for
+ * working with URIs can be provided on top of the interface or externally.
+ * Its primary use is for HTTP requests, but may also be used in other
+ * contexts.
+ *
+ * Instances of this interface are considered immutable; all methods that
+ * might change state MUST be implemented such that they retain the internal
+ * state of the current instance and return an instance that contains the
+ * changed state.
+ *
+ * Typically the Host header will be also be present in the request message.
+ * For server-side requests, the scheme will typically be discoverable in the
+ * server parameters.
+ *
+ * @link http://tools.ietf.org/html/rfc3986 (the URI specification)
+ */
+interface UriInterface
+{
+ /**
+ * Retrieve the scheme component of the URI.
+ *
+ * If no scheme is present, this method MUST return an empty string.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.1.
+ *
+ * The trailing ":" character is not part of the scheme and MUST NOT be
+ * added.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.1
+ * @return string The URI scheme.
+ */
+ public function getScheme();
+
+ /**
+ * Retrieve the authority component of the URI.
+ *
+ * If no authority information is present, this method MUST return an empty
+ * string.
+ *
+ * The authority syntax of the URI is:
+ *
+ * <pre>
+ * [user-info@]host[:port]
+ * </pre>
+ *
+ * If the port component is not set or is the standard port for the current
+ * scheme, it SHOULD NOT be included.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
+ * @return string The URI authority, in "[user-info@]host[:port]" format.
+ */
+ public function getAuthority();
+
+ /**
+ * Retrieve the user information component of the URI.
+ *
+ * If no user information is present, this method MUST return an empty
+ * string.
+ *
+ * If a user is present in the URI, this will return that value;
+ * additionally, if the password is also present, it will be appended to the
+ * user value, with a colon (":") separating the values.
+ *
+ * The trailing "@" character is not part of the user information and MUST
+ * NOT be added.
+ *
+ * @return string The URI user information, in "username[:password]" format.
+ */
+ public function getUserInfo();
+
+ /**
+ * Retrieve the host component of the URI.
+ *
+ * If no host is present, this method MUST return an empty string.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.2.2.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @return string The URI host.
+ */
+ public function getHost();
+
+ /**
+ * Retrieve the port component of the URI.
+ *
+ * If a port is present, and it is non-standard for the current scheme,
+ * this method MUST return it as an integer. If the port is the standard port
+ * used with the current scheme, this method SHOULD return null.
+ *
+ * If no port is present, and no scheme is present, this method MUST return
+ * a null value.
+ *
+ * If no port is present, but a scheme is present, this method MAY return
+ * the standard port for that scheme, but SHOULD return null.
+ *
+ * @return null|int The URI port.
+ */
+ public function getPort();
+
+ /**
+ * Retrieve the path component of the URI.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Normally, the empty path "" and absolute path "/" are considered equal as
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
+ * do this normalization because in contexts with a trimmed base path, e.g.
+ * the front controller, this difference becomes significant. It's the task
+ * of the user to handle both "" and "/".
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.3.
+ *
+ * As an example, if the value should include a slash ("/") not intended as
+ * delimiter between path segments, that value MUST be passed in encoded
+ * form (e.g., "%2F") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
+ * @return string The URI path.
+ */
+ public function getPath();
+
+ /**
+ * Retrieve the query string of the URI.
+ *
+ * If no query string is present, this method MUST return an empty string.
+ *
+ * The leading "?" character is not part of the query and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.4.
+ *
+ * As an example, if a value in a key/value pair of the query string should
+ * include an ampersand ("&") not intended as a delimiter between values,
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
+ * @return string The URI query string.
+ */
+ public function getQuery();
+
+ /**
+ * Retrieve the fragment component of the URI.
+ *
+ * If no fragment is present, this method MUST return an empty string.
+ *
+ * The leading "#" character is not part of the fragment and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.5.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
+ * @return string The URI fragment.
+ */
+ public function getFragment();
+
+ /**
+ * Return an instance with the specified scheme.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified scheme.
+ *
+ * Implementations MUST support the schemes "http" and "https" case
+ * insensitively, and MAY accommodate other schemes if required.
+ *
+ * An empty scheme is equivalent to removing the scheme.
+ *
+ * @param string $scheme The scheme to use with the new instance.
+ * @return static A new instance with the specified scheme.
+ * @throws \InvalidArgumentException for invalid or unsupported schemes.
+ */
+ public function withScheme($scheme);
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; an empty string for the user is equivalent to removing user
+ * information.
+ *
+ * @param string $user The user name to use for authority.
+ * @param null|string $password The password associated with $user.
+ * @return static A new instance with the specified user information.
+ */
+ public function withUserInfo($user, $password = null);
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * An empty host value is equivalent to removing the host.
+ *
+ * @param string $host The hostname to use with the new instance.
+ * @return static A new instance with the specified host.
+ * @throws \InvalidArgumentException for invalid hostnames.
+ */
+ public function withHost($host);
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * Implementations MUST raise an exception for ports outside the
+ * established TCP and UDP port ranges.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param null|int $port The port to use with the new instance; a null value
+ * removes the port information.
+ * @return static A new instance with the specified port.
+ * @throws \InvalidArgumentException for invalid ports.
+ */
+ public function withPort($port);
+
+ /**
+ * Return an instance with the specified path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified path.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * If the path is intended to be domain-relative rather than path relative then
+ * it must begin with a slash ("/"). Paths not starting with a slash ("/")
+ * are assumed to be relative to some base path known to the application or
+ * consumer.
+ *
+ * Users can provide both encoded and decoded path characters.
+ * Implementations ensure the correct encoding as outlined in getPath().
+ *
+ * @param string $path The path to use with the new instance.
+ * @return static A new instance with the specified path.
+ * @throws \InvalidArgumentException for invalid paths.
+ */
+ public function withPath($path);
+
+ /**
+ * Return an instance with the specified query string.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified query string.
+ *
+ * Users can provide both encoded and decoded query characters.
+ * Implementations ensure the correct encoding as outlined in getQuery().
+ *
+ * An empty query string value is equivalent to removing the query string.
+ *
+ * @param string $query The query string to use with the new instance.
+ * @return static A new instance with the specified query string.
+ * @throws \InvalidArgumentException for invalid query strings.
+ */
+ public function withQuery($query);
+
+ /**
+ * Return an instance with the specified URI fragment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified URI fragment.
+ *
+ * Users can provide both encoded and decoded fragment characters.
+ * Implementations ensure the correct encoding as outlined in getFragment().
+ *
+ * An empty fragment value is equivalent to removing the fragment.
+ *
+ * @param string $fragment The fragment to use with the new instance.
+ * @return static A new instance with the specified fragment.
+ */
+ public function withFragment($fragment);
+
+ /**
+ * Return the string representation as a URI reference.
+ *
+ * Depending on which components of the URI are present, the resulting
+ * string is either a full URI or relative reference according to RFC 3986,
+ * Section 4.1. The method concatenates the various components of the URI,
+ * using the appropriate delimiters:
+ *
+ * - If a scheme is present, it MUST be suffixed by ":".
+ * - If an authority is present, it MUST be prefixed by "//".
+ * - The path can be concatenated without delimiters. But there are two
+ * cases where the path has to be adjusted to make the URI reference
+ * valid as PHP does not allow to throw an exception in __toString():
+ * - If the path is rootless and an authority is present, the path MUST
+ * be prefixed by "/".
+ * - If the path is starting with more than one "/" and no authority is
+ * present, the starting slashes MUST be reduced to one.
+ * - If a query is present, it MUST be prefixed by "?".
+ * - If a fragment is present, it MUST be prefixed by "#".
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/vendor/ralouphie/getallheaders/LICENSE b/vendor/ralouphie/getallheaders/LICENSE
new file mode 100644
index 0000000..be5540c
--- /dev/null
+++ b/vendor/ralouphie/getallheaders/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Ralph Khattar
+
+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/ralouphie/getallheaders/composer.json b/vendor/ralouphie/getallheaders/composer.json
new file mode 100644
index 0000000..de8ce62
--- /dev/null
+++ b/vendor/ralouphie/getallheaders/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "ralouphie/getallheaders",
+ "description": "A polyfill for getallheaders.",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5 || ^6.5",
+ "php-coveralls/php-coveralls": "^2.1"
+ },
+ "autoload": {
+ "files": ["src/getallheaders.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "getallheaders\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/vendor/ralouphie/getallheaders/src/getallheaders.php b/vendor/ralouphie/getallheaders/src/getallheaders.php
new file mode 100644
index 0000000..c7285a5
--- /dev/null
+++ b/vendor/ralouphie/getallheaders/src/getallheaders.php
@@ -0,0 +1,46 @@
+<?php
+
+if (!function_exists('getallheaders')) {
+
+ /**
+ * Get all HTTP header key/values as an associative array for the current request.
+ *
+ * @return string[string] The HTTP header key/value pairs.
+ */
+ function getallheaders()
+ {
+ $headers = array();
+
+ $copy_server = array(
+ 'CONTENT_TYPE' => 'Content-Type',
+ 'CONTENT_LENGTH' => 'Content-Length',
+ 'CONTENT_MD5' => 'Content-Md5',
+ );
+
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) === 'HTTP_') {
+ $key = substr($key, 5);
+ if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
+ $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
+ $headers[$key] = $value;
+ }
+ } elseif (isset($copy_server[$key])) {
+ $headers[$copy_server[$key]] = $value;
+ }
+ }
+
+ if (!isset($headers['Authorization'])) {
+ if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
+ $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
+ } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
+ $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
+ $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
+ } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
+ $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
+ }
+ }
+
+ return $headers;
+ }
+
+}
diff --git a/vendor/ramsey/uuid/LICENSE b/vendor/ramsey/uuid/LICENSE
new file mode 100644
index 0000000..1db0ef8
--- /dev/null
+++ b/vendor/ramsey/uuid/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2021 Ben Ramsey <ben@benramsey.com>
+
+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/ramsey/uuid/composer.json b/vendor/ramsey/uuid/composer.json
new file mode 100644
index 0000000..a618595
--- /dev/null
+++ b/vendor/ramsey/uuid/composer.json
@@ -0,0 +1,94 @@
+{
+ "name": "ramsey/uuid",
+ "type": "library",
+ "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+ "keywords": ["uuid", "identifier", "guid"],
+ "homepage": "https://github.com/ramsey/uuid",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ },
+ {
+ "name": "Marijn Huizendveld",
+ "email": "marijn.huizendveld@gmail.com"
+ },
+ {
+ "name": "Thibaud Fabre",
+ "email": "thibaud@aztech.io"
+ }
+ ],
+ "require": {
+ "php": "^5.4 | ^7.0 | ^8.0",
+ "ext-json": "*",
+ "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "require-dev": {
+ "codeception/aspect-mock": "^1 | ^2",
+ "doctrine/annotations": "^1.2",
+ "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
+ "mockery/mockery": "^0.9.11 | ^1",
+ "moontoast/math": "^1.1",
+ "nikic/php-parser": "<=4.5.0",
+ "paragonie/random-lib": "^2",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+ "squizlabs/php_codesniffer": "^3.5",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "suggest": {
+ "ext-ctype": "Provides support for PHP Ctype functions",
+ "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+ "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+ "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+ "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+ "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+ "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type.",
+ "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "replace": {
+ "rhumsaa/uuid": "self.version"
+ },
+ "autoload": {
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Ramsey\\Uuid\\Test\\": "tests/"
+ }
+ },
+ "scripts": {
+ "lint": "parallel-lint src tests",
+ "phpcs": "phpcs src tests --standard=psr2 -sp --colors",
+ "phpunit": "phpunit --verbose --colors=always",
+ "phpunit-coverage": "phpunit --verbose --colors=always --coverage-html build/coverage",
+ "test": [
+ "@lint",
+ "@phpcs",
+ "@phpunit"
+ ]
+ },
+ "support": {
+ "issues": "https://github.com/ramsey/uuid/issues",
+ "rss": "https://github.com/ramsey/uuid/releases.atom",
+ "source": "https://github.com/ramsey/uuid",
+ "wiki": "https://github.com/ramsey/uuid/wiki"
+ }
+}
diff --git a/vendor/ramsey/uuid/src/BinaryUtils.php b/vendor/ramsey/uuid/src/BinaryUtils.php
new file mode 100644
index 0000000..18ea467
--- /dev/null
+++ b/vendor/ramsey/uuid/src/BinaryUtils.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Ramsey\Uuid;
+
+/**
+ * Provides binary math utilities
+ */
+class BinaryUtils
+{
+ /**
+ * Applies the RFC 4122 variant field to the `clock_seq_hi_and_reserved` field
+ *
+ * @param $clockSeqHi
+ * @return int The high field of the clock sequence multiplexed with the variant
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ public static function applyVariant($clockSeqHi)
+ {
+ // Set the variant to RFC 4122
+ $clockSeqHi = $clockSeqHi & 0x3f;
+ $clockSeqHi |= 0x80;
+
+ return $clockSeqHi;
+ }
+
+ /**
+ * Applies the RFC 4122 version number to the `time_hi_and_version` field
+ *
+ * @param string $timeHi
+ * @param integer $version
+ * @return int The high field of the timestamp multiplexed with the version number
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.3
+ */
+ public static function applyVersion($timeHi, $version)
+ {
+ $timeHi = hexdec($timeHi) & 0x0fff;
+ $timeHi |= $version << 12;
+
+ return $timeHi;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php b/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php
new file mode 100644
index 0000000..20656ac
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Builder;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Uuid;
+
+/**
+ * DefaultUuidBuilder is the default UUID builder for ramsey/uuid; it builds
+ * instances of Uuid objects
+ */
+class DefaultUuidBuilder implements UuidBuilderInterface
+{
+ /**
+ * @var NumberConverterInterface
+ */
+ private $converter;
+
+ /**
+ * Constructs the DefaultUuidBuilder
+ *
+ * @param NumberConverterInterface $converter The number converter to use when constructing the Uuid
+ */
+ public function __construct(NumberConverterInterface $converter)
+ {
+ $this->converter = $converter;
+ }
+
+ /**
+ * Builds a Uuid
+ *
+ * @param CodecInterface $codec The codec to use for building this Uuid
+ * @param array $fields An array of fields from which to construct the Uuid;
+ * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
+ * @return Uuid
+ */
+ public function build(CodecInterface $codec, array $fields)
+ {
+ return new Uuid($fields, $this->converter, $codec);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php b/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php
new file mode 100644
index 0000000..7edb6de
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Builder;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\DegradedUuid;
+
+/**
+ * DegradedUuidBuilder builds instances of DegradedUuid
+ */
+class DegradedUuidBuilder implements UuidBuilderInterface
+{
+ /**
+ * @var NumberConverterInterface
+ */
+ private $converter;
+
+ /**
+ * Constructs the DegradedUuidBuilder
+ *
+ * @param NumberConverterInterface $converter The number converter to use when constructing the DegradedUuid
+ */
+ public function __construct(NumberConverterInterface $converter)
+ {
+ $this->converter = $converter;
+ }
+
+ /**
+ * Builds a DegradedUuid
+ *
+ * @param CodecInterface $codec The codec to use for building this DegradedUuid
+ * @param array $fields An array of fields from which to construct the DegradedUuid;
+ * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
+ * @return DegradedUuid
+ */
+ public function build(CodecInterface $codec, array $fields)
+ {
+ return new DegradedUuid($fields, $this->converter, $codec);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php b/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php
new file mode 100644
index 0000000..e4e9901
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Builder;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * UuidBuilderInterface builds instances UuidInterface
+ */
+interface UuidBuilderInterface
+{
+ /**
+ * Builds an instance of a UuidInterface
+ *
+ * @param CodecInterface $codec The codec to use for building this UuidInterface instance
+ * @param array $fields An array of fields from which to construct a UuidInterface instance;
+ * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
+ * @return UuidInterface
+ */
+ public function build(CodecInterface $codec, array $fields);
+}
diff --git a/vendor/ramsey/uuid/src/Codec/CodecInterface.php b/vendor/ramsey/uuid/src/Codec/CodecInterface.php
new file mode 100644
index 0000000..c6c54c7
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/CodecInterface.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Codec;
+
+use InvalidArgumentException;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * CodecInterface represents a UUID coder-decoder
+ */
+interface CodecInterface
+{
+ /**
+ * Encodes a UuidInterface as a string representation of a UUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Hexadecimal string representation of a UUID
+ */
+ public function encode(UuidInterface $uuid);
+
+ /**
+ * Encodes a UuidInterface as a binary representation of a UUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Binary string representation of a UUID
+ */
+ public function encodeBinary(UuidInterface $uuid);
+
+ /**
+ * Decodes a string representation of a UUID into a UuidInterface object instance
+ *
+ * @param string $encodedUuid
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decode($encodedUuid);
+
+ /**
+ * Decodes a binary representation of a UUID into a UuidInterface object instance
+ *
+ * @param string $bytes
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ * @throws InvalidArgumentException if string has not 16 characters
+ */
+ public function decodeBytes($bytes);
+}
diff --git a/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php b/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php
new file mode 100644
index 0000000..3675480
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Codec;
+
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * GuidStringCodec encodes and decodes globally unique identifiers (GUID)
+ *
+ * @link https://en.wikipedia.org/wiki/Globally_unique_identifier
+ */
+class GuidStringCodec extends StringCodec
+{
+ /**
+ * Encodes a UuidInterface as a string representation of a GUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Hexadecimal string representation of a GUID
+ */
+ public function encode(UuidInterface $uuid)
+ {
+ $components = array_values($uuid->getFieldsHex());
+
+ // Swap byte-order on the first three fields
+ $this->swapFields($components);
+
+ return vsprintf(
+ '%08s-%04s-%04s-%02s%02s-%012s',
+ $components
+ );
+ }
+
+ /**
+ * Encodes a UuidInterface as a binary representation of a GUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Binary string representation of a GUID
+ */
+ public function encodeBinary(UuidInterface $uuid)
+ {
+ $components = array_values($uuid->getFieldsHex());
+
+ return hex2bin(implode('', $components));
+ }
+
+ /**
+ * Decodes a string representation of a GUID into a UuidInterface object instance
+ *
+ * @param string $encodedUuid
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decode($encodedUuid)
+ {
+ $components = $this->extractComponents($encodedUuid);
+
+ $this->swapFields($components);
+
+ return $this->getBuilder()->build($this, $this->getFields($components));
+ }
+
+ /**
+ * Decodes a binary representation of a GUID into a UuidInterface object instance
+ *
+ * @param string $bytes
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decodeBytes($bytes)
+ {
+ // Specifically call parent::decode to preserve correct byte order
+ return parent::decode(bin2hex($bytes));
+ }
+
+ /**
+ * Swaps fields to support GUID byte order
+ *
+ * @param array $components An array of UUID components (the UUID exploded on its dashes)
+ * @return void
+ */
+ protected function swapFields(array &$components)
+ {
+ $hex = unpack('H*', pack('L', hexdec($components[0])));
+ $components[0] = $hex[1];
+ $hex = unpack('H*', pack('S', hexdec($components[1])));
+ $components[1] = $hex[1];
+ $hex = unpack('H*', pack('S', hexdec($components[2])));
+ $components[2] = $hex[1];
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php b/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php
new file mode 100644
index 0000000..de91aab
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+namespace Ramsey\Uuid\Codec;
+
+use InvalidArgumentException;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * OrderedTimeCodec optimizes the bytes to increment UUIDs when time goes by, to improve database INSERTs.
+ * The string value will be unchanged from StringCodec. Only works for UUID type 1.
+ */
+class OrderedTimeCodec extends StringCodec
+{
+
+ /**
+ * Encodes a UuidInterface as an optimized binary representation of a UUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Binary string representation of a UUID
+ */
+ public function encodeBinary(UuidInterface $uuid)
+ {
+ $fields = $uuid->getFieldsHex();
+
+ $optimized = [
+ $fields['time_hi_and_version'],
+ $fields['time_mid'],
+ $fields['time_low'],
+ $fields['clock_seq_hi_and_reserved'],
+ $fields['clock_seq_low'],
+ $fields['node'],
+ ];
+
+ return hex2bin(implode('', $optimized));
+ }
+
+ /**
+ * Decodes an optimized binary representation of a UUID into a UuidInterface object instance
+ *
+ * @param string $bytes
+ * @return UuidInterface
+ * @throws InvalidArgumentException if string has not 16 characters
+ */
+ public function decodeBytes($bytes)
+ {
+ if (strlen($bytes) !== 16) {
+ throw new InvalidArgumentException('$bytes string should contain 16 characters.');
+ }
+
+ $hex = unpack('H*', $bytes)[1];
+
+ // Rearrange the fields to their original order
+ $hex = substr($hex, 8, 4) . substr($hex, 12, 4) . substr($hex, 4, 4) . substr($hex, 0, 4) . substr($hex, 16);
+
+ return $this->decode($hex);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Codec/StringCodec.php b/vendor/ramsey/uuid/src/Codec/StringCodec.php
new file mode 100644
index 0000000..f1bc024
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/StringCodec.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Codec;
+
+use InvalidArgumentException;
+use Ramsey\Uuid\Builder\UuidBuilderInterface;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Uuid;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * StringCodec encodes and decodes RFC 4122 UUIDs
+ *
+ * @link http://tools.ietf.org/html/rfc4122
+ */
+class StringCodec implements CodecInterface
+{
+ /**
+ * @var UuidBuilderInterface
+ */
+ private $builder;
+
+ /**
+ * Constructs a StringCodec for use encoding and decoding UUIDs
+ *
+ * @param UuidBuilderInterface $builder The UUID builder to use when encoding UUIDs
+ */
+ public function __construct(UuidBuilderInterface $builder)
+ {
+ $this->builder = $builder;
+ }
+
+ /**
+ * Encodes a UuidInterface as a string representation of a UUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Hexadecimal string representation of a UUID
+ */
+ public function encode(UuidInterface $uuid)
+ {
+ $fields = array_values($uuid->getFieldsHex());
+
+ return vsprintf(
+ '%08s-%04s-%04s-%02s%02s-%012s',
+ $fields
+ );
+ }
+
+ /**
+ * Encodes a UuidInterface as a binary representation of a UUID
+ *
+ * @param UuidInterface $uuid
+ * @return string Binary string representation of a UUID
+ */
+ public function encodeBinary(UuidInterface $uuid)
+ {
+ return hex2bin($uuid->getHex());
+ }
+
+ /**
+ * Decodes a string representation of a UUID into a UuidInterface object instance
+ *
+ * @param string $encodedUuid
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decode($encodedUuid)
+ {
+ $components = $this->extractComponents($encodedUuid);
+ $fields = $this->getFields($components);
+
+ return $this->builder->build($this, $fields);
+ }
+
+ /**
+ * Decodes a binary representation of a UUID into a UuidInterface object instance
+ *
+ * @param string $bytes
+ * @return UuidInterface
+ * @throws InvalidArgumentException if string has not 16 characters
+ */
+ public function decodeBytes($bytes)
+ {
+ if (strlen($bytes) !== 16) {
+ throw new InvalidArgumentException('$bytes string should contain 16 characters.');
+ }
+
+ $hexUuid = unpack('H*', $bytes);
+
+ return $this->decode($hexUuid[1]);
+ }
+
+ /**
+ * Returns the UUID builder
+ *
+ * @return UuidBuilderInterface
+ */
+ protected function getBuilder()
+ {
+ return $this->builder;
+ }
+
+ /**
+ * Returns an array of UUID components (the UUID exploded on its dashes)
+ *
+ * @param string $encodedUuid
+ * @return array
+ * @throws InvalidUuidStringException
+ */
+ protected function extractComponents($encodedUuid)
+ {
+ $nameParsed = str_replace([
+ 'urn:',
+ 'uuid:',
+ '{',
+ '}',
+ '-'
+ ], '', $encodedUuid);
+
+ // We have stripped out the dashes and are breaking up the string using
+ // substr(). In this way, we can accept a full hex value that doesn't
+ // contain dashes.
+ $components = [
+ substr($nameParsed, 0, 8),
+ substr($nameParsed, 8, 4),
+ substr($nameParsed, 12, 4),
+ substr($nameParsed, 16, 4),
+ substr($nameParsed, 20)
+ ];
+
+ $nameParsed = implode('-', $components);
+
+ if (!Uuid::isValid($nameParsed)) {
+ throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid);
+ }
+
+ return $components;
+ }
+
+ /**
+ * Returns the fields that make up this UUID
+ *
+ * @see \Ramsey\Uuid\UuidInterface::getFieldsHex()
+ * @param array $components
+ * @return array
+ */
+ protected function getFields(array $components)
+ {
+ return [
+ 'time_low' => str_pad($components[0], 8, '0', STR_PAD_LEFT),
+ 'time_mid' => str_pad($components[1], 4, '0', STR_PAD_LEFT),
+ 'time_hi_and_version' => str_pad($components[2], 4, '0', STR_PAD_LEFT),
+ 'clock_seq_hi_and_reserved' => str_pad(substr($components[3], 0, 2), 2, '0', STR_PAD_LEFT),
+ 'clock_seq_low' => str_pad(substr($components[3], 2), 2, '0', STR_PAD_LEFT),
+ 'node' => str_pad($components[4], 12, '0', STR_PAD_LEFT)
+ ];
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php b/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php
new file mode 100644
index 0000000..9d13af7
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+namespace Ramsey\Uuid\Codec;
+
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * TimestampFirstCombCodec encodes and decodes COMB UUIDs which have the timestamp as the first 48 bits.
+ * To be used with MySQL, PostgreSQL, Oracle.
+ */
+class TimestampFirstCombCodec extends StringCodec
+{
+ /**
+ * Encodes a UuidInterface as a string representation of a timestamp first COMB UUID
+ *
+ * @param UuidInterface $uuid
+ *
+ * @return string Hexadecimal string representation of a GUID
+ */
+ public function encode(UuidInterface $uuid)
+ {
+ $sixPieceComponents = array_values($uuid->getFieldsHex());
+
+ $this->swapTimestampAndRandomBits($sixPieceComponents);
+
+ return vsprintf(
+ '%08s-%04s-%04s-%02s%02s-%012s',
+ $sixPieceComponents
+ );
+ }
+
+ /**
+ * Encodes a UuidInterface as a binary representation of timestamp first COMB UUID
+ *
+ * @param UuidInterface $uuid
+ *
+ * @return string Binary string representation of timestamp first COMB UUID
+ */
+ public function encodeBinary(UuidInterface $uuid)
+ {
+ $stringEncoding = $this->encode($uuid);
+
+ return hex2bin(str_replace('-', '', $stringEncoding));
+ }
+
+ /**
+ * Decodes a string representation of timestamp first COMB UUID into a UuidInterface object instance
+ *
+ * @param string $encodedUuid
+ *
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decode($encodedUuid)
+ {
+ $fivePieceComponents = $this->extractComponents($encodedUuid);
+
+ $this->swapTimestampAndRandomBits($fivePieceComponents);
+
+ return $this->getBuilder()->build($this, $this->getFields($fivePieceComponents));
+ }
+
+ /**
+ * Decodes a binary representation of timestamp first COMB UUID into a UuidInterface object instance
+ *
+ * @param string $bytes
+ *
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function decodeBytes($bytes)
+ {
+ return $this->decode(bin2hex($bytes));
+ }
+
+ /**
+ * Swaps the first 48 bits with the last 48 bits
+ *
+ * @param array $components An array of UUID components (the UUID exploded on its dashes)
+ *
+ * @return void
+ */
+ protected function swapTimestampAndRandomBits(array &$components)
+ {
+ $last48Bits = $components[4];
+ if (count($components) == 6) {
+ $last48Bits = $components[5];
+ $components[5] = $components[0] . $components[1];
+ } else {
+ $components[4] = $components[0] . $components[1];
+ }
+
+ $components[0] = substr($last48Bits, 0, 8);
+ $components[1] = substr($last48Bits, 8, 4);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php b/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php
new file mode 100644
index 0000000..240f613
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+namespace Ramsey\Uuid\Codec;
+
+/**
+ * TimestampLastCombCodec encodes and decodes COMB UUIDs which have the timestamp as the last 48 bits.
+ * To be used with MSSQL.
+ */
+class TimestampLastCombCodec extends StringCodec
+{
+}
diff --git a/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php b/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php
new file mode 100644
index 0000000..d235122
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter\Number;
+
+use Moontoast\Math\BigNumber;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+
+/**
+ * BigNumberConverter converts UUIDs from hexadecimal characters into
+ * moontoast/math `BigNumber` representations of integers and vice versa
+ */
+class BigNumberConverter implements NumberConverterInterface
+{
+ /**
+ * Converts a hexadecimal number into a `Moontoast\Math\BigNumber` representation
+ *
+ * @param string $hex The hexadecimal string representation to convert
+ * @return BigNumber
+ */
+ public function fromHex($hex)
+ {
+ $number = BigNumber::convertToBase10($hex, 16);
+
+ return new BigNumber($number);
+ }
+
+ /**
+ * Converts an integer or `Moontoast\Math\BigNumber` integer representation
+ * into a hexadecimal string representation
+ *
+ * @param int|string|BigNumber $integer An integer or `Moontoast\Math\BigNumber`
+ * @return string Hexadecimal string
+ */
+ public function toHex($integer)
+ {
+ if (!$integer instanceof BigNumber) {
+ $integer = new BigNumber($integer);
+ }
+
+ return BigNumber::convertFromBase10($integer, 16);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php b/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php
new file mode 100644
index 0000000..96a011c
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter\Number;
+
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+
+/**
+ * DegradedNumberConverter throws `UnsatisfiedDependencyException` exceptions
+ * if attempting to use number conversion functionality in an environment that
+ * does not support large integers (i.e. when moontoast/math is not available)
+ */
+class DegradedNumberConverter implements NumberConverterInterface
+{
+ /**
+ * Throws an `UnsatisfiedDependencyException`
+ *
+ * @param string $hex The hexadecimal string representation to convert
+ * @return void
+ * @throws UnsatisfiedDependencyException
+ */
+ public function fromHex($hex)
+ {
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' without support for large '
+ . 'integers, since integer is an unsigned '
+ . '128-bit integer; Moontoast\Math\BigNumber is required.'
+ );
+ }
+
+ /**
+ * Throws an `UnsatisfiedDependencyException`
+ *
+ * @param mixed $integer An integer representation to convert
+ * @return void
+ * @throws UnsatisfiedDependencyException
+ */
+ public function toHex($integer)
+ {
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' without support for large '
+ . 'integers, since integer is an unsigned '
+ . '128-bit integer; Moontoast\Math\BigNumber is required. '
+ );
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php b/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php
new file mode 100644
index 0000000..b978e2e
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter;
+
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * NumberConverterInterface converts UUIDs from hexadecimal characters into
+ * representations of integers and vice versa
+ */
+interface NumberConverterInterface
+{
+ /**
+ * Converts a hexadecimal number into an integer representation of the number
+ *
+ * The integer representation returned may be an object or a string
+ * representation of the integer, depending on the implementation.
+ *
+ * @param string $hex The hexadecimal string representation to convert
+ * @return mixed
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ */
+ public function fromHex($hex);
+
+ /**
+ * Converts an integer representation into a hexadecimal string representation
+ * of the number
+ *
+ * @param mixed $integer An integer representation to convert; this may be
+ * a true integer, a string integer, or a object representation that
+ * this converter can understand
+ * @return string Hexadecimal string
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ */
+ public function toHex($integer);
+}
diff --git a/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php b/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php
new file mode 100644
index 0000000..112f722
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter\Time;
+
+use Moontoast\Math\BigNumber;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+
+/**
+ * BigNumberTimeConverter uses the moontoast/math library's `BigNumber` to
+ * provide facilities for converting parts of time into representations that may
+ * be used in UUIDs
+ */
+class BigNumberTimeConverter implements TimeConverterInterface
+{
+ /**
+ * Uses the provided seconds and micro-seconds to calculate the time_low,
+ * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
+ *
+ * @param string $seconds
+ * @param string $microSeconds
+ * @return string[] An array containing `low`, `mid`, and `high` keys
+ * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+ */
+ public function calculateTime($seconds, $microSeconds)
+ {
+ $uuidTime = new BigNumber('0');
+
+ $sec = new BigNumber($seconds);
+ $sec->multiply('10000000');
+
+ $usec = new BigNumber($microSeconds);
+ $usec->multiply('10');
+
+ $uuidTime
+ ->add($sec)
+ ->add($usec)
+ ->add('122192928000000000');
+
+ $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16));
+
+ return [
+ 'low' => substr($uuidTimeHex, 8),
+ 'mid' => substr($uuidTimeHex, 4, 4),
+ 'hi' => substr($uuidTimeHex, 0, 4),
+ ];
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php b/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php
new file mode 100644
index 0000000..b94589c
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter\Time;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * DegradedTimeConverter throws `UnsatisfiedDependencyException` exceptions
+ * if attempting to use time conversion functionality in an environment that
+ * does not support large integers (i.e. when moontoast/math is not available)
+ */
+class DegradedTimeConverter implements TimeConverterInterface
+{
+ /**
+ * Throws an `UnsatisfiedDependencyException`
+ *
+ * @param string $seconds
+ * @param string $microSeconds
+ * @return void
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and `Moontoast\Math\BigNumber` is not present
+ */
+ public function calculateTime($seconds, $microSeconds)
+ {
+ throw new UnsatisfiedDependencyException(
+ 'When calling ' . __METHOD__ . ' on a 32-bit system, '
+ . 'Moontoast\Math\BigNumber must be present.'
+ );
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php b/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php
new file mode 100644
index 0000000..57c882d
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter\Time;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+
+/**
+ * PhpTimeConverter uses built-in PHP functions and standard math operations
+ * available to the PHP programming language to provide facilities for
+ * converting parts of time into representations that may be used in UUIDs
+ */
+class PhpTimeConverter implements TimeConverterInterface
+{
+ /**
+ * Uses the provided seconds and micro-seconds to calculate the time_low,
+ * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
+ *
+ * @param string $seconds
+ * @param string $microSeconds
+ * @return string[] An array containing `low`, `mid`, and `high` keys
+ * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+ */
+ public function calculateTime($seconds, $microSeconds)
+ {
+ // 0x01b21dd213814000 is the number of 100-ns intervals between the
+ // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
+ $uuidTime = ($seconds * 10000000) + ($microSeconds * 10) + 0x01b21dd213814000;
+
+ return [
+ 'low' => sprintf('%08x', $uuidTime & 0xffffffff),
+ 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff),
+ 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff),
+ ];
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php b/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php
new file mode 100644
index 0000000..23cf164
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Converter;
+
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * TimeConverterInterface provides facilities for converting parts of time into
+ * representations that may be used in UUIDs
+ */
+interface TimeConverterInterface
+{
+ /**
+ * Uses the provided seconds and micro-seconds to calculate the time_low,
+ * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
+ *
+ * @param string $seconds
+ * @param string $microSeconds
+ * @return string[] An array guaranteed to contain `low`, `mid`, and `hi` keys
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+ */
+ public function calculateTime($seconds, $microSeconds);
+}
diff --git a/vendor/ramsey/uuid/src/DegradedUuid.php b/vendor/ramsey/uuid/src/DegradedUuid.php
new file mode 100644
index 0000000..4e11272
--- /dev/null
+++ b/vendor/ramsey/uuid/src/DegradedUuid.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use DateTime;
+use Moontoast\Math\BigNumber;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
+
+/**
+ * DegradedUuid represents an RFC 4122 UUID on 32-bit systems
+ *
+ * @see Uuid
+ */
+class DegradedUuid extends Uuid
+{
+ /**
+ * @inheritdoc
+ */
+ public function getDateTime()
+ {
+ if ($this->getVersion() != 1) {
+ throw new UnsupportedOperationException('Not a time-based UUID');
+ }
+
+ $time = $this->converter->fromHex($this->getTimestampHex());
+
+ $ts = new BigNumber($time, 20);
+ $ts->subtract('122192928000000000');
+ $ts->divide('10000000.0');
+ $ts->floor();
+ $unixTime = $ts->getValue();
+
+ return new DateTime("@{$unixTime}");
+ }
+
+ /**
+ * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
+ * called on a 32-bit system
+ *
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system
+ */
+ public function getFields()
+ {
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some '
+ . 'values overflow the system max integer value'
+ . '; consider calling getFieldsHex instead'
+ );
+ }
+
+ /**
+ * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
+ * called on a 32-bit system
+ *
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system
+ */
+ public function getNode()
+ {
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node '
+ . 'is an unsigned 48-bit integer and can overflow the system '
+ . 'max integer value'
+ . '; consider calling getNodeHex instead'
+ );
+ }
+
+ /**
+ * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
+ * called on a 32-bit system
+ *
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system
+ */
+ public function getTimeLow()
+ {
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low '
+ . 'is an unsigned 32-bit integer and can overflow the system '
+ . 'max integer value'
+ . '; consider calling getTimeLowHex instead'
+ );
+ }
+
+ /**
+ * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
+ * called on a 32-bit system
+ *
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system
+ * @throws UnsupportedOperationException If this UUID is not a version 1 UUID
+ */
+ public function getTimestamp()
+ {
+ if ($this->getVersion() != 1) {
+ throw new UnsupportedOperationException('Not a time-based UUID');
+ }
+
+ throw new UnsatisfiedDependencyException(
+ 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp '
+ . 'is an unsigned 60-bit integer and can overflow the system '
+ . 'max integer value'
+ . '; consider calling getTimestampHex instead'
+ );
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php b/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php
new file mode 100644
index 0000000..7df0e8c
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Exception;
+
+use InvalidArgumentException;
+
+/**
+ * Thrown to indicate that the parsed UUID string is invalid.
+ */
+class InvalidUuidStringException extends InvalidArgumentException
+{
+}
diff --git a/vendor/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php b/vendor/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php
new file mode 100644
index 0000000..89c7396
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException;
+
+/**
+ * Thrown to indicate that the requested operation has dependencies that have not
+ * been satisfied.
+ */
+class UnsatisfiedDependencyException extends RuntimeException
+{
+}
diff --git a/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php b/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php
new file mode 100644
index 0000000..4340947
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException;
+
+/**
+ * Thrown to indicate that the requested operation is not supported.
+ */
+class UnsupportedOperationException extends RuntimeException
+{
+}
diff --git a/vendor/ramsey/uuid/src/FeatureSet.php b/vendor/ramsey/uuid/src/FeatureSet.php
new file mode 100644
index 0000000..2027b9e
--- /dev/null
+++ b/vendor/ramsey/uuid/src/FeatureSet.php
@@ -0,0 +1,335 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Generator\PeclUuidTimeGenerator;
+use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
+use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
+use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\Number\BigNumberConverter;
+use Ramsey\Uuid\Converter\Number\DegradedNumberConverter;
+use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter;
+use Ramsey\Uuid\Converter\Time\DegradedTimeConverter;
+use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
+use Ramsey\Uuid\Provider\Time\SystemTimeProvider;
+use Ramsey\Uuid\Builder\UuidBuilderInterface;
+use Ramsey\Uuid\Builder\DefaultUuidBuilder;
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Codec\StringCodec;
+use Ramsey\Uuid\Codec\GuidStringCodec;
+use Ramsey\Uuid\Builder\DegradedUuidBuilder;
+use Ramsey\Uuid\Generator\RandomGeneratorFactory;
+use Ramsey\Uuid\Generator\RandomGeneratorInterface;
+use Ramsey\Uuid\Generator\TimeGeneratorFactory;
+use Ramsey\Uuid\Generator\TimeGeneratorInterface;
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+
+/**
+ * FeatureSet detects and exposes available features in the current environment
+ * (32- or 64-bit, available dependencies, etc.)
+ */
+class FeatureSet
+{
+ /**
+ * @var bool
+ */
+ private $disableBigNumber = false;
+
+ /**
+ * @var bool
+ */
+ private $disable64Bit = false;
+
+ /**
+ * @var bool
+ */
+ private $ignoreSystemNode = false;
+
+ /**
+ * @var bool
+ */
+ private $enablePecl = false;
+
+ /**
+ * @var UuidBuilderInterface
+ */
+ private $builder;
+
+ /**
+ * @var CodecInterface
+ */
+ private $codec;
+
+ /**
+ * @var NodeProviderInterface
+ */
+ private $nodeProvider;
+
+ /**
+ * @var NumberConverterInterface
+ */
+ private $numberConverter;
+
+ /**
+ * @var RandomGeneratorInterface
+ */
+ private $randomGenerator;
+
+ /**
+ * @var TimeGeneratorInterface
+ */
+ private $timeGenerator;
+
+ /**
+ * Constructs a `FeatureSet` for use by a `UuidFactory` to determine or set
+ * features available to the environment
+ *
+ * @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec`
+ * @param bool $force32Bit Whether to force the use of 32-bit functionality
+ * (primarily for testing purposes)
+ * @param bool $forceNoBigNumber Whether to disable the use of moontoast/math
+ * `BigNumber` (primarily for testing purposes)
+ * @param bool $ignoreSystemNode Whether to disable attempts to check for
+ * the system host ID (primarily for testing purposes)
+ * @param bool $enablePecl Whether to enable the use of the `PeclUuidTimeGenerator`
+ * to generate version 1 UUIDs
+ */
+ public function __construct(
+ $useGuids = false,
+ $force32Bit = false,
+ $forceNoBigNumber = false,
+ $ignoreSystemNode = false,
+ $enablePecl = false
+ ) {
+ $this->disableBigNumber = $forceNoBigNumber;
+ $this->disable64Bit = $force32Bit;
+ $this->ignoreSystemNode = $ignoreSystemNode;
+ $this->enablePecl = $enablePecl;
+
+ $this->numberConverter = $this->buildNumberConverter();
+ $this->builder = $this->buildUuidBuilder();
+ $this->codec = $this->buildCodec($useGuids);
+ $this->nodeProvider = $this->buildNodeProvider();
+ $this->randomGenerator = $this->buildRandomGenerator();
+ $this->setTimeProvider(new SystemTimeProvider());
+ }
+
+ /**
+ * Returns the builder configured for this environment
+ *
+ * @return UuidBuilderInterface
+ */
+ public function getBuilder()
+ {
+ return $this->builder;
+ }
+
+ /**
+ * Returns the UUID UUID coder-decoder configured for this environment
+ *
+ * @return CodecInterface
+ */
+ public function getCodec()
+ {
+ return $this->codec;
+ }
+
+ /**
+ * Returns the system node ID provider configured for this environment
+ *
+ * @return NodeProviderInterface
+ */
+ public function getNodeProvider()
+ {
+ return $this->nodeProvider;
+ }
+
+ /**
+ * Returns the number converter configured for this environment
+ *
+ * @return NumberConverterInterface
+ */
+ public function getNumberConverter()
+ {
+ return $this->numberConverter;
+ }
+
+ /**
+ * Returns the random UUID generator configured for this environment
+ *
+ * @return RandomGeneratorInterface
+ */
+ public function getRandomGenerator()
+ {
+ return $this->randomGenerator;
+ }
+
+ /**
+ * Returns the time-based UUID generator configured for this environment
+ *
+ * @return TimeGeneratorInterface
+ */
+ public function getTimeGenerator()
+ {
+ return $this->timeGenerator;
+ }
+
+ /**
+ * Sets the time provider for use in this environment
+ *
+ * @param TimeProviderInterface $timeProvider
+ */
+ public function setTimeProvider(TimeProviderInterface $timeProvider)
+ {
+ $this->timeGenerator = $this->buildTimeGenerator($timeProvider);
+ }
+
+ /**
+ * Determines which UUID coder-decoder to use and returns the configured
+ * codec for this environment
+ *
+ * @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec`
+ * @return CodecInterface
+ */
+ protected function buildCodec($useGuids = false)
+ {
+ if ($useGuids) {
+ return new GuidStringCodec($this->builder);
+ }
+
+ return new StringCodec($this->builder);
+ }
+
+ /**
+ * Determines which system node ID provider to use and returns the configured
+ * system node ID provider for this environment
+ *
+ * @return NodeProviderInterface
+ */
+ protected function buildNodeProvider()
+ {
+ if ($this->ignoreSystemNode) {
+ return new RandomNodeProvider();
+ }
+
+ return new FallbackNodeProvider([
+ new SystemNodeProvider(),
+ new RandomNodeProvider()
+ ]);
+ }
+
+ /**
+ * Determines which number converter to use and returns the configured
+ * number converter for this environment
+ *
+ * @return NumberConverterInterface
+ */
+ protected function buildNumberConverter()
+ {
+ if ($this->hasBigNumber()) {
+ return new BigNumberConverter();
+ }
+
+ return new DegradedNumberConverter();
+ }
+
+ /**
+ * Determines which random UUID generator to use and returns the configured
+ * random UUID generator for this environment
+ *
+ * @return RandomGeneratorInterface
+ */
+ protected function buildRandomGenerator()
+ {
+ return (new RandomGeneratorFactory())->getGenerator();
+ }
+
+ /**
+ * Determines which time-based UUID generator to use and returns the configured
+ * time-based UUID generator for this environment
+ *
+ * @param TimeProviderInterface $timeProvider
+ * @return TimeGeneratorInterface
+ */
+ protected function buildTimeGenerator(TimeProviderInterface $timeProvider)
+ {
+ if ($this->enablePecl) {
+ return new PeclUuidTimeGenerator();
+ }
+
+ return (new TimeGeneratorFactory(
+ $this->nodeProvider,
+ $this->buildTimeConverter(),
+ $timeProvider
+ ))->getGenerator();
+ }
+
+ /**
+ * Determines which time converter to use and returns the configured
+ * time converter for this environment
+ *
+ * @return TimeConverterInterface
+ */
+ protected function buildTimeConverter()
+ {
+ if ($this->is64BitSystem()) {
+ return new PhpTimeConverter();
+ }
+
+ if ($this->hasBigNumber()) {
+ return new BigNumberTimeConverter();
+ }
+
+ return new DegradedTimeConverter();
+ }
+
+ /**
+ * Determines which UUID builder to use and returns the configured UUID
+ * builder for this environment
+ *
+ * @return UuidBuilderInterface
+ */
+ protected function buildUuidBuilder()
+ {
+ if ($this->is64BitSystem()) {
+ return new DefaultUuidBuilder($this->numberConverter);
+ }
+
+ return new DegradedUuidBuilder($this->numberConverter);
+ }
+
+ /**
+ * Returns true if the system has `Moontoast\Math\BigNumber`
+ *
+ * @return bool
+ */
+ protected function hasBigNumber()
+ {
+ return class_exists('Moontoast\Math\BigNumber') && !$this->disableBigNumber;
+ }
+
+ /**
+ * Returns true if the system is 64-bit, false otherwise
+ *
+ * @return bool
+ */
+ protected function is64BitSystem()
+ {
+ return PHP_INT_SIZE == 8 && !$this->disable64Bit;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/CombGenerator.php b/vendor/ramsey/uuid/src/Generator/CombGenerator.php
new file mode 100644
index 0000000..1d4a5f6
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/CombGenerator.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * CombGenerator provides functionality to generate COMB (combined GUID/timestamp)
+ * sequential UUIDs
+ *
+ * @link https://en.wikipedia.org/wiki/Globally_unique_identifier#Sequential_algorithms
+ */
+class CombGenerator implements RandomGeneratorInterface
+{
+ const TIMESTAMP_BYTES = 6;
+
+ /**
+ * @var RandomGeneratorInterface
+ */
+ private $randomGenerator;
+
+ /**
+ * @var NumberConverterInterface
+ */
+ private $converter;
+
+ /**
+ * Constructs a `CombGenerator` using a random-number generator and a number converter
+ *
+ * @param RandomGeneratorInterface $generator Random-number generator for the non-time part.
+ * @param NumberConverterInterface $numberConverter Instance of number converter.
+ */
+ public function __construct(RandomGeneratorInterface $generator, NumberConverterInterface $numberConverter)
+ {
+ $this->converter = $numberConverter;
+ $this->randomGenerator = $generator;
+ }
+
+ /**
+ * Generates a string of binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException if length is not a positive integer
+ * @throws Exception
+ */
+ public function generate($length)
+ {
+ if ($length < self::TIMESTAMP_BYTES || $length < 0) {
+ throw new InvalidArgumentException('Length must be a positive integer.');
+ }
+
+ $hash = '';
+
+ if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) {
+ $hash = $this->randomGenerator->generate($length - self::TIMESTAMP_BYTES);
+ }
+
+ $lsbTime = str_pad($this->converter->toHex($this->timestamp()), self::TIMESTAMP_BYTES * 2, '0', STR_PAD_LEFT);
+
+ return hex2bin(str_pad(bin2hex($hash), $length - self::TIMESTAMP_BYTES, '0') . $lsbTime);
+ }
+
+ /**
+ * Returns current timestamp as integer, precise to 0.00001 seconds
+ *
+ * @return string
+ */
+ private function timestamp()
+ {
+ $time = explode(' ', microtime(false));
+
+ return $time[1] . substr($time[0], 2, 5);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php b/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php
new file mode 100644
index 0000000..5c5ccb2
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\BinaryUtils;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+
+/**
+ * DefaultTimeGenerator provides functionality to generate strings of binary
+ * data for version 1 UUIDs based on a host ID, sequence number, and the current
+ * time
+ */
+class DefaultTimeGenerator implements TimeGeneratorInterface
+{
+ /**
+ * @var NodeProviderInterface
+ */
+ private $nodeProvider;
+
+ /**
+ * @var TimeConverterInterface
+ */
+ private $timeConverter;
+
+ /**
+ * @var TimeProviderInterface
+ */
+ private $timeProvider;
+
+ /**
+ * Constructs a `DefaultTimeGenerator` using a node provider, time converter,
+ * and time provider
+ *
+ * @param NodeProviderInterface $nodeProvider
+ * @param TimeConverterInterface $timeConverter
+ * @param TimeProviderInterface $timeProvider
+ */
+ public function __construct(
+ NodeProviderInterface $nodeProvider,
+ TimeConverterInterface $timeConverter,
+ TimeProviderInterface $timeProvider
+ ) {
+ $this->nodeProvider = $nodeProvider;
+ $this->timeConverter = $timeConverter;
+ $this->timeProvider = $timeProvider;
+ }
+
+ /**
+ * Generate a version 1 UUID from a host ID, sequence number, and the current time
+ *
+ * If $node is not given, we will attempt to obtain the local hardware
+ * address. If $clockSeq is given, it is used as the sequence number;
+ * otherwise a random 14-bit sequence number is chosen.
+ *
+ * @param int|string $node A 48-bit number representing the hardware address
+ * This number may be represented as an integer or a hexadecimal string.
+ * @param int $clockSeq A 14-bit number used to help avoid duplicates that
+ * could arise when the clock is set backwards in time or if the node ID
+ * changes.
+ * @return string A binary string
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function generate($node = null, $clockSeq = null)
+ {
+ $node = $this->getValidNode($node);
+
+ if ($clockSeq === null) {
+ // Not using "stable storage"; see RFC 4122, Section 4.2.1.1
+ $clockSeq = random_int(0, 0x3fff);
+ }
+
+ // Create a 60-bit time value as a count of 100-nanosecond intervals
+ // since 00:00:00.00, 15 October 1582
+ $timeOfDay = $this->timeProvider->currentTime();
+ $uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']);
+
+ $timeHi = BinaryUtils::applyVersion($uuidTime['hi'], 1);
+ $clockSeqHi = BinaryUtils::applyVariant($clockSeq >> 8);
+
+ $hex = vsprintf(
+ '%08s%04s%04s%02s%02s%012s',
+ [
+ $uuidTime['low'],
+ $uuidTime['mid'],
+ sprintf('%04x', $timeHi),
+ sprintf('%02x', $clockSeqHi),
+ sprintf('%02x', $clockSeq & 0xff),
+ $node,
+ ]
+ );
+
+ return hex2bin($hex);
+ }
+
+ /**
+ * Uses the node provider given when constructing this instance to get
+ * the node ID (usually a MAC address)
+ *
+ * @param string|int $node A node value that may be used to override the node provider
+ * @return string Hexadecimal representation of the node ID
+ * @throws InvalidArgumentException
+ * @throws Exception
+ */
+ protected function getValidNode($node)
+ {
+ if ($node === null) {
+ $node = $this->nodeProvider->getNode();
+ }
+
+ // Convert the node to hex, if it is still an integer
+ if (is_int($node)) {
+ $node = sprintf('%012x', $node);
+ }
+
+ if (!ctype_xdigit($node) || strlen($node) > 12) {
+ throw new InvalidArgumentException('Invalid node value');
+ }
+
+ return strtolower(sprintf('%012s', $node));
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/MtRandGenerator.php b/vendor/ramsey/uuid/src/Generator/MtRandGenerator.php
new file mode 100644
index 0000000..8d4b5f9
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/MtRandGenerator.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * MtRandRandomGenerator provides functionality to generate strings of random
+ * binary data using the `mt_rand()` PHP function
+ *
+ * @deprecated The mt_rand() function is not a reliable source of randomness.
+ * The default RandomBytesGenerator, which uses the random_bytes() function,
+ * is recommended as the safest and most reliable source of randomness.
+ * <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
+ * @link http://php.net/mt_rand
+ */
+class MtRandGenerator implements RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ */
+ public function generate($length)
+ {
+ $bytes = '';
+
+ for ($i = 1; $i <= $length; $i++) {
+ $bytes = chr(mt_rand(0, 255)) . $bytes;
+ }
+
+ return $bytes;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/OpenSslGenerator.php b/vendor/ramsey/uuid/src/Generator/OpenSslGenerator.php
new file mode 100644
index 0000000..47abf9b
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/OpenSslGenerator.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * OpenSslRandomGenerator provides functionality to generate strings of random
+ * binary data using the `openssl_random_pseudo_bytes()` PHP function
+ *
+ * The use of this generator requires PHP to be compiled using the
+ * `--with-openssl` option.
+ *
+ * @deprecated The openssl_random_pseudo_bytes() function is not a reliable
+ * source of randomness. The default RandomBytesGenerator, which uses the
+ * random_bytes() function, is recommended as the safest and most reliable
+ * source of randomness.
+ * <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
+ * @link http://php.net/openssl_random_pseudo_bytes
+ */
+class OpenSslGenerator implements RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ */
+ public function generate($length)
+ {
+ return openssl_random_pseudo_bytes($length);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php b/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php
new file mode 100644
index 0000000..fc2ef7e
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * PeclUuidRandomGenerator provides functionality to generate strings of random
+ * binary data using the PECL UUID PHP extension
+ *
+ * @link https://pecl.php.net/package/uuid
+ */
+class PeclUuidRandomGenerator implements RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ */
+ public function generate($length)
+ {
+ $uuid = uuid_create(UUID_TYPE_RANDOM);
+
+ return uuid_parse($uuid);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php b/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php
new file mode 100644
index 0000000..7ccf16f
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * PeclUuidTimeGenerator provides functionality to generate strings of binary
+ * data for version 1 UUIDs using the PECL UUID PHP extension
+ *
+ * @link https://pecl.php.net/package/uuid
+ */
+class PeclUuidTimeGenerator implements TimeGeneratorInterface
+{
+ /**
+ * Generate a version 1 UUID using the PECL UUID extension
+ *
+ * @param int|string $node Not used in this context
+ * @param int $clockSeq Not used in this context
+ * @return string A binary string
+ */
+ public function generate($node = null, $clockSeq = null)
+ {
+ $uuid = uuid_create(UUID_TYPE_TIME);
+
+ return uuid_parse($uuid);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php b/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php
new file mode 100644
index 0000000..cc3d379
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Exception;
+
+/**
+ * RandomBytesGenerator provides functionality to generate strings of random
+ * binary data using `random_bytes()` function in PHP 7+ or paragonie/random_compat
+ *
+ * @link http://php.net/random_bytes
+ * @link https://github.com/paragonie/random_compat
+ */
+class RandomBytesGenerator implements RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function generate($length)
+ {
+ return random_bytes($length);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php b/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php
new file mode 100644
index 0000000..3911062
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * A factory for retrieving a random generator, based on the environment
+ */
+class RandomGeneratorFactory
+{
+ /**
+ * Returns a default random generator, based on the current environment
+ *
+ * @return RandomGeneratorInterface
+ */
+ public static function getGenerator()
+ {
+ return new RandomBytesGenerator();
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php b/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php
new file mode 100644
index 0000000..b791d60
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * RandomGeneratorInterface provides functionality to generate strings of random
+ * binary data
+ */
+interface RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function generate($length);
+}
diff --git a/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php b/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php
new file mode 100644
index 0000000..5aa0e88
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use RandomLib\Generator;
+use RandomLib\Factory;
+
+/**
+ * RandomLibAdapter provides functionality to generate strings of random
+ * binary data using the paragonie/random-lib library
+ *
+ * @link https://packagist.org/packages/paragonie/random-lib
+ */
+class RandomLibAdapter implements RandomGeneratorInterface
+{
+ /**
+ * @var Generator
+ */
+ private $generator;
+
+ /**
+ * Constructs a `RandomLibAdapter` using a `RandomLib\Generator`
+ *
+ * By default, if no `Generator` is passed in, this creates a high-strength
+ * generator to use when generating random binary data.
+ *
+ * @param Generator $generator An paragonie/random-lib `Generator`
+ */
+ public function __construct(Generator $generator = null)
+ {
+ $this->generator = $generator;
+
+ if ($this->generator === null) {
+ $factory = new Factory();
+
+ $this->generator = $factory->getHighStrengthGenerator();
+ }
+ }
+
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ */
+ public function generate($length)
+ {
+ return $this->generator->generate($length);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/SodiumRandomGenerator.php b/vendor/ramsey/uuid/src/Generator/SodiumRandomGenerator.php
new file mode 100644
index 0000000..f4ccf85
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/SodiumRandomGenerator.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+/**
+ * SodiumRandomGenerator provides functionality to generate strings of random
+ * binary data using the PECL libsodium extension
+ *
+ * @deprecated As of PHP 7.2.0, the libsodium extension is bundled with PHP, and
+ * the random_bytes() PHP function is now the recommended method for
+ * generating random byes. The default RandomBytesGenerator uses the
+ * random_bytes() function.
+ * <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
+ * @link http://pecl.php.net/package/libsodium
+ * @link https://paragonie.com/book/pecl-libsodium
+ */
+class SodiumRandomGenerator implements RandomGeneratorInterface
+{
+ /**
+ * Generates a string of random binary data of the specified length
+ *
+ * @param integer $length The number of bytes of random binary data to generate
+ * @return string A binary string
+ */
+ public function generate($length)
+ {
+ return \Sodium\randombytes_buf($length);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php b/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php
new file mode 100644
index 0000000..24d501b
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+
+/**
+ * A factory for retrieving a time generator, based on the environment
+ */
+class TimeGeneratorFactory
+{
+ /**
+ * @var NodeProviderInterface
+ */
+ private $nodeProvider;
+
+ /**
+ * @var TimeConverterInterface
+ */
+ private $timeConverter;
+
+ /**
+ * @var TimeProviderInterface
+ */
+ private $timeProvider;
+
+ /**
+ * Constructs a `TimeGeneratorFactory` using a node provider, time converter,
+ * and time provider
+ *
+ * @param NodeProviderInterface $nodeProvider
+ * @param TimeConverterInterface $timeConverter
+ * @param TimeProviderInterface $timeProvider
+ */
+ public function __construct(
+ NodeProviderInterface $nodeProvider,
+ TimeConverterInterface $timeConverter,
+ TimeProviderInterface $timeProvider
+ ) {
+ $this->nodeProvider = $nodeProvider;
+ $this->timeConverter = $timeConverter;
+ $this->timeProvider = $timeProvider;
+ }
+
+ /**
+ * Returns a default time generator, based on the current environment
+ *
+ * @return TimeGeneratorInterface
+ */
+ public function getGenerator()
+ {
+ return new DefaultTimeGenerator(
+ $this->nodeProvider,
+ $this->timeConverter,
+ $this->timeProvider
+ );
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php b/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php
new file mode 100644
index 0000000..27c7459
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Generator;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * TimeGeneratorInterface provides functionality to generate strings of binary
+ * data for version 1 UUIDs based on a host ID, sequence number, and the current
+ * time
+ */
+interface TimeGeneratorInterface
+{
+ /**
+ * Generate a version 1 UUID from a host ID, sequence number, and the current time
+ *
+ * @param int|string $node A 48-bit number representing the hardware address
+ * This number may be represented as an integer or a hexadecimal string.
+ * @param int $clockSeq A 14-bit number used to help avoid duplicates that
+ * could arise when the clock is set backwards in time or if the node ID
+ * changes.
+ * @return string A binary string
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function generate($node = null, $clockSeq = null);
+}
diff --git a/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php b/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php
new file mode 100644
index 0000000..83488ab
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider\Node;
+
+use Exception;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+
+/**
+ * FallbackNodeProvider attempts to gain the system host ID from an array of
+ * providers, falling back to the next in line in the event a host ID can not be
+ * obtained
+ */
+class FallbackNodeProvider implements NodeProviderInterface
+{
+ /**
+ * @var NodeProviderInterface[]
+ */
+ private $nodeProviders;
+
+ /**
+ * Constructs a `FallbackNodeProvider` using an array of node providers
+ *
+ * @param NodeProviderInterface[] $providers Array of node providers
+ */
+ public function __construct(array $providers)
+ {
+ $this->nodeProviders = $providers;
+ }
+
+ /**
+ * Returns the system node ID by iterating over an array of node providers
+ * and returning the first non-empty value found
+ *
+ * @return string System node ID as a hexadecimal string
+ * @throws Exception
+ */
+ public function getNode()
+ {
+ foreach ($this->nodeProviders as $provider) {
+ if ($node = $provider->getNode()) {
+ return $node;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php b/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php
new file mode 100644
index 0000000..79ec63c
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider\Node;
+
+use Exception;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+
+/**
+ * RandomNodeProvider provides functionality to generate a random node ID, in
+ * the event that the node ID could not be obtained from the host system
+ *
+ * @link http://tools.ietf.org/html/rfc4122#section-4.5
+ */
+class RandomNodeProvider implements NodeProviderInterface
+{
+ /**
+ * Returns the system node ID
+ *
+ * @return string System node ID as a hexadecimal string
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function getNode()
+ {
+ $nodeBytes = random_bytes(6);
+
+ // Split the node bytes for math on 32-bit systems.
+ $nodeMsb = substr($nodeBytes, 0, 3);
+ $nodeLsb = substr($nodeBytes, 3);
+
+ // Set the multicast bit; see RFC 4122, section 4.5.
+ $nodeMsb = hex2bin(
+ str_pad(
+ dechex(hexdec(bin2hex($nodeMsb)) | 0x010000),
+ 6,
+ '0',
+ STR_PAD_LEFT
+ )
+ );
+
+ // Recombine the node bytes.
+ $node = $nodeMsb . $nodeLsb;
+
+ return str_pad(bin2hex($node), 12, '0', STR_PAD_LEFT);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php b/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php
new file mode 100644
index 0000000..5701513
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider\Node;
+
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+
+/**
+ * SystemNodeProvider provides functionality to get the system node ID (MAC
+ * address) using external system calls
+ */
+class SystemNodeProvider implements NodeProviderInterface
+{
+ /**
+ * Returns the system node ID
+ *
+ * @return string|false System node ID as a hexadecimal string, or false if it is not found
+ */
+ public function getNode()
+ {
+ static $node = null;
+
+ if ($node !== null) {
+ return $node;
+ }
+
+ $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/';
+ $matches = [];
+
+ // first try a linux specific way
+ $node = $this->getSysfs();
+
+ // Search the ifconfig output for all MAC addresses and return
+ // the first one found
+ if ($node === false) {
+ if (preg_match_all($pattern, $this->getIfconfig(), $matches, PREG_PATTERN_ORDER)) {
+ $node = $matches[1][0];
+ }
+ }
+ if ($node !== false) {
+ $node = str_replace([':', '-'], '', $node);
+ }
+ return $node;
+ }
+
+ /**
+ * Returns the network interface configuration for the system
+ *
+ * @codeCoverageIgnore
+ * @return string
+ */
+ protected function getIfconfig()
+ {
+ if (strpos(strtolower(ini_get('disable_functions')), 'passthru') !== false) {
+ return '';
+ }
+
+ ob_start();
+ switch (strtoupper(substr(constant('PHP_OS'), 0, 3))) {
+ case 'WIN':
+ passthru('ipconfig /all 2>&1');
+ break;
+ case 'DAR':
+ passthru('ifconfig 2>&1');
+ break;
+ case 'FRE':
+ passthru('netstat -i -f link 2>&1');
+ break;
+ case 'LIN':
+ default:
+ passthru('netstat -ie 2>&1');
+ break;
+ }
+
+ return ob_get_clean();
+ }
+
+ /**
+ * Returns mac address from the first system interface via the sysfs interface
+ *
+ * @return string|bool
+ */
+ protected function getSysfs()
+ {
+ $mac = false;
+
+ if (strtoupper(constant('PHP_OS')) === 'LINUX') {
+ $addressPaths = glob('/sys/class/net/*/address', GLOB_NOSORT);
+
+ if (empty($addressPaths)) {
+ return false;
+ }
+
+ $macs = [];
+ array_walk($addressPaths, function ($addressPath) use (&$macs) {
+ if (is_readable($addressPath)) {
+ $macs[] = file_get_contents($addressPath);
+ }
+ });
+
+ $macs = array_map('trim', $macs);
+
+ // remove invalid entries
+ $macs = array_filter($macs, function ($mac) {
+ return
+ // localhost adapter
+ $mac !== '00:00:00:00:00:00' &&
+ // must match mac adress
+ preg_match('/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i', $mac);
+ });
+
+ $mac = reset($macs);
+ }
+
+ return $mac;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php b/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php
new file mode 100644
index 0000000..b6f721f
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider;
+
+use Exception;
+
+/**
+ * NodeProviderInterface provides functionality to get the node ID (or host ID
+ * in the form of the system's MAC address) from a specific type of node provider
+ */
+interface NodeProviderInterface
+{
+ /**
+ * Returns the system node ID
+ *
+ * @return string System node ID as a hexadecimal string
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function getNode();
+}
diff --git a/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php b/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php
new file mode 100644
index 0000000..79a9d04
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider\Time;
+
+use InvalidArgumentException;
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+
+/**
+ * FixedTimeProvider uses an previously-generated timestamp to provide the time
+ *
+ * This provider allows the use of a previously-generated timestamp, such as one
+ * stored in a database, when creating version 1 UUIDs.
+ */
+class FixedTimeProvider implements TimeProviderInterface
+{
+ /**
+ * @var int[] Array containing `sec` and `usec` components of a timestamp
+ */
+ private $fixedTime;
+
+ /**
+ * Constructs a `FixedTimeProvider` using the provided `$timestamp`
+ *
+ * @param int[] Array containing `sec` and `usec` components of a timestamp
+ * @throws InvalidArgumentException if the `$timestamp` does not contain `sec` or `usec` components
+ */
+ public function __construct(array $timestamp)
+ {
+ if (!array_key_exists('sec', $timestamp) || !array_key_exists('usec', $timestamp)) {
+ throw new InvalidArgumentException('Array must contain sec and usec keys.');
+ }
+
+ $this->fixedTime = $timestamp;
+ }
+
+ /**
+ * Sets the `usec` component of the timestamp
+ *
+ * @param int $value The `usec` value to set
+ */
+ public function setUsec($value)
+ {
+ $this->fixedTime['usec'] = $value;
+ }
+
+ /**
+ * Sets the `sec` component of the timestamp
+ *
+ * @param int $value The `sec` value to set
+ */
+ public function setSec($value)
+ {
+ $this->fixedTime['sec'] = $value;
+ }
+
+ /**
+ * Returns a timestamp array
+ *
+ * @return int[] Array containing `sec` and `usec` components of a timestamp
+ */
+ public function currentTime()
+ {
+ return $this->fixedTime;
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php b/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php
new file mode 100644
index 0000000..6442985
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider\Time;
+
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+
+/**
+ * SystemTimeProvider uses built-in PHP functions to provide the time
+ */
+class SystemTimeProvider implements TimeProviderInterface
+{
+ /**
+ * Returns a timestamp array
+ *
+ * @return int[] Array containing `sec` and `usec` components of a timestamp
+ */
+ public function currentTime()
+ {
+ return gettimeofday();
+ }
+}
diff --git a/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php b/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php
new file mode 100644
index 0000000..ef8099d
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid\Provider;
+
+/**
+ * TimeProviderInterface provides functionality to get the time from a specific
+ * type of time provider
+ */
+interface TimeProviderInterface
+{
+ /**
+ * Returns a timestamp array
+ *
+ * @return int[] Array guaranteed to contain `sec` and `usec` components of a timestamp
+ */
+ public function currentTime();
+}
diff --git a/vendor/ramsey/uuid/src/Uuid.php b/vendor/ramsey/uuid/src/Uuid.php
new file mode 100644
index 0000000..f1369b8
--- /dev/null
+++ b/vendor/ramsey/uuid/src/Uuid.php
@@ -0,0 +1,781 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use DateTime;
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use ReturnTypeWillChange;
+
+/**
+ * Represents a universally unique identifier (UUID), according to RFC 4122.
+ *
+ * This class provides immutable UUID objects (the Uuid class) and the static
+ * methods `uuid1()`, `uuid3()`, `uuid4()`, and `uuid5()` for generating version
+ * 1, 3, 4, and 5 UUIDs as specified in RFC 4122.
+ *
+ * If all you want is a unique ID, you should probably call `uuid1()` or `uuid4()`.
+ * Note that `uuid1()` may compromise privacy since it creates a UUID containing
+ * the computer’s network address. `uuid4()` creates a random UUID.
+ *
+ * @link http://tools.ietf.org/html/rfc4122
+ * @link http://en.wikipedia.org/wiki/Universally_unique_identifier
+ * @link http://docs.python.org/3/library/uuid.html
+ * @link http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html
+ */
+class Uuid implements UuidInterface
+{
+ /**
+ * When this namespace is specified, the name string is a fully-qualified domain name.
+ * @link http://tools.ietf.org/html/rfc4122#appendix-C
+ */
+ const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
+
+ /**
+ * When this namespace is specified, the name string is a URL.
+ * @link http://tools.ietf.org/html/rfc4122#appendix-C
+ */
+ const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
+
+ /**
+ * When this namespace is specified, the name string is an ISO OID.
+ * @link http://tools.ietf.org/html/rfc4122#appendix-C
+ */
+ const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
+
+ /**
+ * When this namespace is specified, the name string is an X.500 DN in DER or a text output format.
+ * @link http://tools.ietf.org/html/rfc4122#appendix-C
+ */
+ const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
+
+ /**
+ * The nil UUID is special form of UUID that is specified to have all 128 bits set to zero.
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.7
+ */
+ const NIL = '00000000-0000-0000-0000-000000000000';
+
+ /**
+ * Reserved for NCS compatibility.
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ const RESERVED_NCS = 0;
+
+ /**
+ * Specifies the UUID layout given in RFC 4122.
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ const RFC_4122 = 2;
+
+ /**
+ * Reserved for Microsoft compatibility.
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ const RESERVED_MICROSOFT = 6;
+
+ /**
+ * Reserved for future definition.
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ const RESERVED_FUTURE = 7;
+
+ /**
+ * Regular expression pattern for matching a valid UUID of any variant.
+ */
+ const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$';
+
+ /**
+ * Version 1 (time-based) UUID object constant identifier
+ */
+ const UUID_TYPE_TIME = 1;
+
+ /**
+ * Version 2 (identifier-based) UUID object constant identifier
+ */
+ const UUID_TYPE_IDENTIFIER = 2;
+
+ /**
+ * Version 3 (name-based and hashed with MD5) UUID object constant identifier
+ */
+ const UUID_TYPE_HASH_MD5 = 3;
+
+ /**
+ * Version 4 (random) UUID object constant identifier
+ */
+ const UUID_TYPE_RANDOM = 4;
+
+ /**
+ * Version 5 (name-based and hashed with SHA1) UUID object constant identifier
+ */
+ const UUID_TYPE_HASH_SHA1 = 5;
+
+ /**
+ * The factory to use when creating UUIDs.
+ * @var UuidFactoryInterface
+ */
+ private static $factory = null;
+
+ /**
+ * The codec to use when encoding or decoding UUID strings.
+ * @var CodecInterface
+ */
+ protected $codec;
+
+ /**
+ * The fields that make up this UUID.
+ *
+ * This is initialized to the nil value.
+ *
+ * @var array
+ * @see UuidInterface::getFieldsHex()
+ */
+ protected $fields = [
+ 'time_low' => '00000000',
+ 'time_mid' => '0000',
+ 'time_hi_and_version' => '0000',
+ 'clock_seq_hi_and_reserved' => '00',
+ 'clock_seq_low' => '00',
+ 'node' => '000000000000',
+ ];
+
+ /**
+ * The number converter to use for converting hex values to/from integers.
+ * @var NumberConverterInterface
+ */
+ protected $converter;
+
+ /**
+ * Creates a universally unique identifier (UUID) from an array of fields.
+ *
+ * Unless you're making advanced use of this library to generate identifiers
+ * that deviate from RFC 4122, you probably do not want to instantiate a
+ * UUID directly. Use the static methods, instead:
+ *
+ * ```
+ * use Ramsey\Uuid\Uuid;
+ *
+ * $timeBasedUuid = Uuid::uuid1();
+ * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/');
+ * $randomUuid = Uuid::uuid4();
+ * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/');
+ * ```
+ *
+ * @param array $fields An array of fields from which to construct a UUID;
+ * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
+ * @param NumberConverterInterface $converter The number converter to use
+ * for converting hex values to/from integers.
+ * @param CodecInterface $codec The codec to use when encoding or decoding
+ * UUID strings.
+ */
+ public function __construct(
+ array $fields,
+ NumberConverterInterface $converter,
+ CodecInterface $codec
+ ) {
+ $this->fields = $fields;
+ $this->codec = $codec;
+ $this->converter = $converter;
+ }
+
+ /**
+ * Converts this UUID object to a string when the object is used in any
+ * string context.
+ *
+ * @return string
+ * @link http://www.php.net/manual/en/language.oop5.magic.php#object.tostring
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Converts this UUID object to a string when the object is serialized
+ * with `json_encode()`
+ *
+ * @return string
+ * @link http://php.net/manual/en/class.jsonserializable.php
+ */
+ #[\ReturnTypeWillChange]
+ public function jsonSerialize()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Converts this UUID object to a string when the object is serialized
+ * with `serialize()`
+ *
+ * @return string
+ * @link http://php.net/manual/en/class.serializable.php
+ */
+ #[ReturnTypeWillChange]
+ public function serialize()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * @return array{string: string}
+ */
+ #[ReturnTypeWillChange]
+ public function __serialize()
+ {
+ return ['string' => $this->toString()];
+ }
+
+ /**
+ * Re-constructs the object from its serialized form.
+ *
+ * @param string $serialized
+ * @link http://php.net/manual/en/class.serializable.php
+ * @throws InvalidUuidStringException
+ */
+ #[ReturnTypeWillChange]
+ public function unserialize($serialized)
+ {
+ $uuid = self::fromString($serialized);
+ $this->codec = $uuid->codec;
+ $this->converter = $uuid->converter;
+ $this->fields = $uuid->fields;
+ }
+
+ /**
+ * @param array{string: string} $serialized
+ * @return void
+ * @throws InvalidUuidStringException
+ */
+ #[ReturnTypeWillChange]
+ public function __unserialize(array $serialized)
+ {
+ // @codeCoverageIgnoreStart
+ if (!isset($serialized['string'])) {
+ throw new InvalidUuidStringException();
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->unserialize($serialized['string']);
+ }
+
+ public function compareTo(UuidInterface $other)
+ {
+ if ($this->getMostSignificantBitsHex() < $other->getMostSignificantBitsHex()) {
+ return -1;
+ }
+
+ if ($this->getMostSignificantBitsHex() > $other->getMostSignificantBitsHex()) {
+ return 1;
+ }
+
+ if ($this->getLeastSignificantBitsHex() < $other->getLeastSignificantBitsHex()) {
+ return -1;
+ }
+
+ if ($this->getLeastSignificantBitsHex() > $other->getLeastSignificantBitsHex()) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ public function equals($other)
+ {
+ if (!$other instanceof UuidInterface) {
+ return false;
+ }
+
+ return $this->compareTo($other) == 0;
+ }
+
+ public function getBytes()
+ {
+ return $this->codec->encodeBinary($this);
+ }
+
+ /**
+ * Returns the high field of the clock sequence multiplexed with the variant
+ * (bits 65-72 of the UUID).
+ *
+ * @return int Unsigned 8-bit integer value of clock_seq_hi_and_reserved
+ */
+ public function getClockSeqHiAndReserved()
+ {
+ return hexdec($this->getClockSeqHiAndReservedHex());
+ }
+
+ public function getClockSeqHiAndReservedHex()
+ {
+ return $this->fields['clock_seq_hi_and_reserved'];
+ }
+
+ /**
+ * Returns the low field of the clock sequence (bits 73-80 of the UUID).
+ *
+ * @return int Unsigned 8-bit integer value of clock_seq_low
+ */
+ public function getClockSeqLow()
+ {
+ return hexdec($this->getClockSeqLowHex());
+ }
+
+ public function getClockSeqLowHex()
+ {
+ return $this->fields['clock_seq_low'];
+ }
+
+ /**
+ * Returns the clock sequence value associated with this UUID.
+ *
+ * For UUID version 1, the clock sequence is used to help avoid
+ * duplicates that could arise when the clock is set backwards in time
+ * or if the node ID changes.
+ *
+ * For UUID version 3 or 5, the clock sequence is a 14-bit value
+ * constructed from a name as described in RFC 4122, Section 4.3.
+ *
+ * For UUID version 4, clock sequence is a randomly or pseudo-randomly
+ * generated 14-bit value as described in RFC 4122, Section 4.4.
+ *
+ * @return int Unsigned 14-bit integer value of clock sequence
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.5
+ */
+ public function getClockSequence()
+ {
+ return ($this->getClockSeqHiAndReserved() & 0x3f) << 8 | $this->getClockSeqLow();
+ }
+
+ public function getClockSequenceHex()
+ {
+ return sprintf('%04x', $this->getClockSequence());
+ }
+
+ public function getNumberConverter()
+ {
+ return $this->converter;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getDateTime()
+ {
+ if ($this->getVersion() != 1) {
+ throw new UnsupportedOperationException('Not a time-based UUID');
+ }
+
+ $unixTimeNanoseconds = $this->getTimestamp() - 0x01b21dd213814000;
+ $unixTime = ($unixTimeNanoseconds - $unixTimeNanoseconds % 1e7) / 1e7;
+
+ return new DateTime("@{$unixTime}");
+ }
+
+ /**
+ * Returns an array of the fields of this UUID, with keys named according
+ * to the RFC 4122 names for the fields.
+ *
+ * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer
+ * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer
+ * * **time_hi_and_version**: The high field of the timestamp multiplexed with
+ * the version number, an unsigned 16-bit integer
+ * * **clock_seq_hi_and_reserved**: The high field of the clock sequence
+ * multiplexed with the variant, an unsigned 8-bit integer
+ * * **clock_seq_low**: The low field of the clock sequence, an unsigned
+ * 8-bit integer
+ * * **node**: The spatially unique node identifier, an unsigned 48-bit
+ * integer
+ *
+ * @return array The UUID fields represented as integer values
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.2
+ */
+ public function getFields()
+ {
+ return [
+ 'time_low' => $this->getTimeLow(),
+ 'time_mid' => $this->getTimeMid(),
+ 'time_hi_and_version' => $this->getTimeHiAndVersion(),
+ 'clock_seq_hi_and_reserved' => $this->getClockSeqHiAndReserved(),
+ 'clock_seq_low' => $this->getClockSeqLow(),
+ 'node' => $this->getNode(),
+ ];
+ }
+
+ public function getFieldsHex()
+ {
+ return $this->fields;
+ }
+
+ public function getHex()
+ {
+ return str_replace('-', '', $this->toString());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getInteger()
+ {
+ return $this->converter->fromHex($this->getHex());
+ }
+
+ /**
+ * Returns the least significant 64 bits of this UUID's 128 bit value.
+ *
+ * @return mixed Converted representation of the unsigned 64-bit integer value
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ */
+ public function getLeastSignificantBits()
+ {
+ return $this->converter->fromHex($this->getLeastSignificantBitsHex());
+ }
+
+ public function getLeastSignificantBitsHex()
+ {
+ return sprintf(
+ '%02s%02s%012s',
+ $this->fields['clock_seq_hi_and_reserved'],
+ $this->fields['clock_seq_low'],
+ $this->fields['node']
+ );
+ }
+
+ /**
+ * Returns the most significant 64 bits of this UUID's 128 bit value.
+ *
+ * @return mixed Converted representation of the unsigned 64-bit integer value
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ */
+ public function getMostSignificantBits()
+ {
+ return $this->converter->fromHex($this->getMostSignificantBitsHex());
+ }
+
+ public function getMostSignificantBitsHex()
+ {
+ return sprintf(
+ '%08s%04s%04s',
+ $this->fields['time_low'],
+ $this->fields['time_mid'],
+ $this->fields['time_hi_and_version']
+ );
+ }
+
+ /**
+ * Returns the node value associated with this UUID
+ *
+ * For UUID version 1, the node field consists of an IEEE 802 MAC
+ * address, usually the host address. For systems with multiple IEEE
+ * 802 addresses, any available one can be used. The lowest addressed
+ * octet (octet number 10) contains the global/local bit and the
+ * unicast/multicast bit, and is the first octet of the address
+ * transmitted on an 802.3 LAN.
+ *
+ * For systems with no IEEE address, a randomly or pseudo-randomly
+ * generated value may be used; see RFC 4122, Section 4.5. The
+ * multicast bit must be set in such addresses, in order that they
+ * will never conflict with addresses obtained from network cards.
+ *
+ * For UUID version 3 or 5, the node field is a 48-bit value constructed
+ * from a name as described in RFC 4122, Section 4.3.
+ *
+ * For UUID version 4, the node field is a randomly or pseudo-randomly
+ * generated 48-bit value as described in RFC 4122, Section 4.4.
+ *
+ * @return int Unsigned 48-bit integer value of node
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.6
+ */
+ public function getNode()
+ {
+ return hexdec($this->getNodeHex());
+ }
+
+ public function getNodeHex()
+ {
+ return $this->fields['node'];
+ }
+
+ /**
+ * Returns the high field of the timestamp multiplexed with the version
+ * number (bits 49-64 of the UUID).
+ *
+ * @return int Unsigned 16-bit integer value of time_hi_and_version
+ */
+ public function getTimeHiAndVersion()
+ {
+ return hexdec($this->getTimeHiAndVersionHex());
+ }
+
+ public function getTimeHiAndVersionHex()
+ {
+ return $this->fields['time_hi_and_version'];
+ }
+
+ /**
+ * Returns the low field of the timestamp (the first 32 bits of the UUID).
+ *
+ * @return int Unsigned 32-bit integer value of time_low
+ */
+ public function getTimeLow()
+ {
+ return hexdec($this->getTimeLowHex());
+ }
+
+ public function getTimeLowHex()
+ {
+ return $this->fields['time_low'];
+ }
+
+ /**
+ * Returns the middle field of the timestamp (bits 33-48 of the UUID).
+ *
+ * @return int Unsigned 16-bit integer value of time_mid
+ */
+ public function getTimeMid()
+ {
+ return hexdec($this->getTimeMidHex());
+ }
+
+ public function getTimeMidHex()
+ {
+ return $this->fields['time_mid'];
+ }
+
+ /**
+ * Returns the timestamp value associated with this UUID.
+ *
+ * The 60 bit timestamp value is constructed from the time_low,
+ * time_mid, and time_hi fields of this UUID. The resulting
+ * timestamp is measured in 100-nanosecond units since midnight,
+ * October 15, 1582 UTC.
+ *
+ * The timestamp value is only meaningful in a time-based UUID, which
+ * has version type 1. If this UUID is not a time-based UUID then
+ * this method throws UnsupportedOperationException.
+ *
+ * @return int Unsigned 60-bit integer value of the timestamp
+ * @throws UnsupportedOperationException If this UUID is not a version 1 UUID
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.4
+ */
+ public function getTimestamp()
+ {
+ if ($this->getVersion() != 1) {
+ throw new UnsupportedOperationException('Not a time-based UUID');
+ }
+
+ return hexdec($this->getTimestampHex());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getTimestampHex()
+ {
+ if ($this->getVersion() != 1) {
+ throw new UnsupportedOperationException('Not a time-based UUID');
+ }
+
+ return sprintf(
+ '%03x%04s%08s',
+ ($this->getTimeHiAndVersion() & 0x0fff),
+ $this->fields['time_mid'],
+ $this->fields['time_low']
+ );
+ }
+
+ public function getUrn()
+ {
+ return 'urn:uuid:' . $this->toString();
+ }
+
+ public function getVariant()
+ {
+ $clockSeq = $this->getClockSeqHiAndReserved();
+
+ if (0 === ($clockSeq & 0x80)) {
+ return self::RESERVED_NCS;
+ }
+
+ if (0 === ($clockSeq & 0x40)) {
+ return self::RFC_4122;
+ }
+
+ if (0 === ($clockSeq & 0x20)) {
+ return self::RESERVED_MICROSOFT;
+ }
+
+ return self::RESERVED_FUTURE;
+ }
+
+ public function getVersion()
+ {
+ if ($this->getVariant() == self::RFC_4122) {
+ return (int) (($this->getTimeHiAndVersion() >> 12) & 0x0f);
+ }
+
+ return null;
+ }
+
+ public function toString()
+ {
+ return $this->codec->encode($this);
+ }
+
+ /**
+ * Returns the currently set factory used to create UUIDs.
+ *
+ * @return UuidFactoryInterface
+ */
+ public static function getFactory()
+ {
+ if (!self::$factory) {
+ self::$factory = new UuidFactory();
+ }
+
+ return self::$factory;
+ }
+
+ /**
+ * Sets the factory used to create UUIDs.
+ *
+ * @param UuidFactoryInterface $factory
+ */
+ public static function setFactory(UuidFactoryInterface $factory)
+ {
+ self::$factory = $factory;
+ }
+
+ /**
+ * Creates a UUID from a byte string.
+ *
+ * @param string $bytes
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ * @throws InvalidArgumentException
+ */
+ public static function fromBytes($bytes)
+ {
+ return self::getFactory()->fromBytes($bytes);
+ }
+
+ /**
+ * Creates a UUID from the string standard representation.
+ *
+ * @param string $name A string that specifies a UUID
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public static function fromString($name)
+ {
+ return self::getFactory()->fromString($name);
+ }
+
+ /**
+ * Creates a UUID from a 128-bit integer string.
+ *
+ * @param string $integer String representation of 128-bit integer
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidUuidStringException
+ */
+ public static function fromInteger($integer)
+ {
+ return self::getFactory()->fromInteger($integer);
+ }
+
+ /**
+ * Check if a string is a valid UUID.
+ *
+ * @param string $uuid The string UUID to test
+ * @return boolean
+ */
+ public static function isValid($uuid)
+ {
+ $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid);
+
+ if ($uuid == self::NIL) {
+ return true;
+ }
+
+ if (!preg_match('/' . self::VALID_PATTERN . '/D', $uuid)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Generate a version 1 UUID from a host ID, sequence number, and the current time.
+ *
+ * @param int|string $node A 48-bit number representing the hardware address
+ * This number may be represented as an integer or a hexadecimal string.
+ * @param int $clockSeq A 14-bit number used to help avoid duplicates that
+ * could arise when the clock is set backwards in time or if the node ID
+ * changes.
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public static function uuid1($node = null, $clockSeq = null)
+ {
+ return self::getFactory()->uuid1($node, $clockSeq);
+ }
+
+ /**
+ * Generate a version 3 UUID based on the MD5 hash of a namespace identifier
+ * (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public static function uuid3($ns, $name)
+ {
+ return self::getFactory()->uuid3($ns, $name);
+ }
+
+ /**
+ * Generate a version 4 (random) UUID.
+ *
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception
+ */
+ public static function uuid4()
+ {
+ return self::getFactory()->uuid4();
+ }
+
+ /**
+ * Generate a version 5 UUID based on the SHA-1 hash of a namespace
+ * identifier (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public static function uuid5($ns, $name)
+ {
+ return self::getFactory()->uuid5($ns, $name);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/UuidFactory.php b/vendor/ramsey/uuid/src/UuidFactory.php
new file mode 100644
index 0000000..5a57b09
--- /dev/null
+++ b/vendor/ramsey/uuid/src/UuidFactory.php
@@ -0,0 +1,315 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Provider\NodeProviderInterface;
+use Ramsey\Uuid\Generator\RandomGeneratorInterface;
+use Ramsey\Uuid\Generator\TimeGeneratorInterface;
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Builder\UuidBuilderInterface;
+
+class UuidFactory implements UuidFactoryInterface
+{
+ /**
+ * @var CodecInterface
+ */
+ private $codec = null;
+
+ /**
+ * @var NodeProviderInterface
+ */
+ private $nodeProvider = null;
+
+ /**
+ * @var NumberConverterInterface
+ */
+ private $numberConverter = null;
+
+ /**
+ * @var RandomGeneratorInterface
+ */
+ private $randomGenerator = null;
+
+ /**
+ * @var TimeGeneratorInterface
+ */
+ private $timeGenerator = null;
+
+ /**
+ * @var UuidBuilderInterface
+ */
+ private $uuidBuilder = null;
+
+ /**
+ * Constructs a `UuidFactory` for creating `Ramsey\Uuid\UuidInterface` instances
+ *
+ * @param FeatureSet $features A set of features for use when creating UUIDs
+ */
+ public function __construct(FeatureSet $features = null)
+ {
+ $features = $features ?: new FeatureSet();
+
+ $this->codec = $features->getCodec();
+ $this->nodeProvider = $features->getNodeProvider();
+ $this->numberConverter = $features->getNumberConverter();
+ $this->randomGenerator = $features->getRandomGenerator();
+ $this->timeGenerator = $features->getTimeGenerator();
+ $this->uuidBuilder = $features->getBuilder();
+ }
+
+ /**
+ * Returns the UUID coder-decoder used by this factory
+ *
+ * @return CodecInterface
+ */
+ public function getCodec()
+ {
+ return $this->codec;
+ }
+
+ /**
+ * Sets the UUID coder-decoder used by this factory
+ *
+ * @param CodecInterface $codec
+ */
+ public function setCodec(CodecInterface $codec)
+ {
+ $this->codec = $codec;
+ }
+
+ /**
+ * Returns the system node ID provider used by this factory
+ *
+ * @return NodeProviderInterface
+ */
+ public function getNodeProvider()
+ {
+ return $this->nodeProvider;
+ }
+
+ /**
+ * Returns the random UUID generator used by this factory
+ *
+ * @return RandomGeneratorInterface
+ */
+ public function getRandomGenerator()
+ {
+ return $this->randomGenerator;
+ }
+
+ /**
+ * Returns the time-based UUID generator used by this factory
+ *
+ * @return TimeGeneratorInterface
+ */
+ public function getTimeGenerator()
+ {
+ return $this->timeGenerator;
+ }
+
+ /**
+ * Sets the time-based UUID generator this factory will use to generate version 1 UUIDs
+ *
+ * @param TimeGeneratorInterface $generator
+ */
+ public function setTimeGenerator(TimeGeneratorInterface $generator)
+ {
+ $this->timeGenerator = $generator;
+ }
+
+ /**
+ * Returns the number converter used by this factory
+ *
+ * @return NumberConverterInterface
+ */
+ public function getNumberConverter()
+ {
+ return $this->numberConverter;
+ }
+
+ /**
+ * Sets the random UUID generator this factory will use to generate version 4 UUIDs
+ *
+ * @param RandomGeneratorInterface $generator
+ */
+ public function setRandomGenerator(RandomGeneratorInterface $generator)
+ {
+ $this->randomGenerator = $generator;
+ }
+
+ /**
+ * Sets the number converter this factory will use
+ *
+ * @param NumberConverterInterface $converter
+ */
+ public function setNumberConverter(NumberConverterInterface $converter)
+ {
+ $this->numberConverter = $converter;
+ }
+
+ /**
+ * Returns the UUID builder this factory uses when creating `Uuid` instances
+ *
+ * @return UuidBuilderInterface $builder
+ */
+ public function getUuidBuilder()
+ {
+ return $this->uuidBuilder;
+ }
+
+ /**
+ * Sets the UUID builder this factory will use when creating `Uuid` instances
+ *
+ * @param UuidBuilderInterface $builder
+ */
+ public function setUuidBuilder(UuidBuilderInterface $builder)
+ {
+ $this->uuidBuilder = $builder;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fromBytes($bytes)
+ {
+ return $this->codec->decodeBytes($bytes);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fromString($uuid)
+ {
+ $uuid = strtolower($uuid);
+ return $this->codec->decode($uuid);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fromInteger($integer)
+ {
+ $hex = $this->numberConverter->toHex($integer);
+ $hex = str_pad($hex, 32, '0', STR_PAD_LEFT);
+
+ return $this->fromString($hex);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function uuid1($node = null, $clockSeq = null)
+ {
+ $bytes = $this->timeGenerator->generate($node, $clockSeq);
+ $hex = bin2hex($bytes);
+
+ return $this->uuidFromHashedName($hex, 1);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function uuid3($ns, $name)
+ {
+ return $this->uuidFromNsAndName($ns, $name, 3, 'md5');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function uuid4()
+ {
+ $bytes = $this->randomGenerator->generate(16);
+
+ // When converting the bytes to hex, it turns into a 32-character
+ // hexadecimal string that looks a lot like an MD5 hash, so at this
+ // point, we can just pass it to uuidFromHashedName.
+ $hex = bin2hex($bytes);
+
+ return $this->uuidFromHashedName($hex, 4);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function uuid5($ns, $name)
+ {
+ return $this->uuidFromNsAndName($ns, $name, 5, 'sha1');
+ }
+
+ /**
+ * Returns a `Uuid`
+ *
+ * Uses the configured builder and codec and the provided array of hexadecimal
+ * value UUID fields to construct a `Uuid` object.
+ *
+ * @param array $fields An array of fields from which to construct a UUID;
+ * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
+ * @return UuidInterface
+ */
+ public function uuid(array $fields)
+ {
+ return $this->uuidBuilder->build($this->codec, $fields);
+ }
+
+ /**
+ * Returns a version 3 or 5 namespaced `Uuid`
+ *
+ * @param string|UuidInterface $ns The UUID namespace to use
+ * @param string $name The string to hash together with the namespace
+ * @param int $version The version of UUID to create (3 or 5)
+ * @param string $hashFunction The hash function to use when hashing together
+ * the namespace and name
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ protected function uuidFromNsAndName($ns, $name, $version, $hashFunction)
+ {
+ if (!($ns instanceof UuidInterface)) {
+ $ns = $this->codec->decode($ns);
+ }
+
+ $hash = call_user_func($hashFunction, ($ns->getBytes() . $name));
+
+ return $this->uuidFromHashedName($hash, $version);
+ }
+
+ /**
+ * Returns a `Uuid` created from `$hash` with the version field set to `$version`
+ * and the variant field set for RFC 4122
+ *
+ * @param string $hash The hash to use when creating the UUID
+ * @param int $version The UUID version to set for this hash (1, 3, 4, or 5)
+ * @return UuidInterface
+ */
+ protected function uuidFromHashedName($hash, $version)
+ {
+ $timeHi = BinaryUtils::applyVersion(substr($hash, 12, 4), $version);
+ $clockSeqHi = BinaryUtils::applyVariant(hexdec(substr($hash, 16, 2)));
+
+ $fields = [
+ 'time_low' => substr($hash, 0, 8),
+ 'time_mid' => substr($hash, 8, 4),
+ 'time_hi_and_version' => str_pad(dechex($timeHi), 4, '0', STR_PAD_LEFT),
+ 'clock_seq_hi_and_reserved' => str_pad(dechex($clockSeqHi), 2, '0', STR_PAD_LEFT),
+ 'clock_seq_low' => substr($hash, 18, 2),
+ 'node' => substr($hash, 20, 12),
+ ];
+
+ return $this->uuid($fields);
+ }
+}
diff --git a/vendor/ramsey/uuid/src/UuidFactoryInterface.php b/vendor/ramsey/uuid/src/UuidFactoryInterface.php
new file mode 100644
index 0000000..1c1651d
--- /dev/null
+++ b/vendor/ramsey/uuid/src/UuidFactoryInterface.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * UuidFactoryInterface defines common functionality all `UuidFactory` instances
+ * must implement
+ */
+interface UuidFactoryInterface
+{
+ /**
+ * Generate a version 1 UUID from a host ID, sequence number, and the current time.
+ *
+ * @param int|string|null $node A 48-bit number representing the hardware address
+ * This number may be represented as an integer or a hexadecimal string.
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that
+ * could arise when the clock is set backwards in time or if the node ID
+ * changes.
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+ public function uuid1($node = null, $clockSeq = null);
+
+ /**
+ * Generate a version 3 UUID based on the MD5 hash of a namespace identifier
+ * (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function uuid3($ns, $name);
+
+ /**
+ * Generate a version 4 (random) UUID.
+ *
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception
+ */
+ public function uuid4();
+
+ /**
+ * Generate a version 5 UUID based on the SHA-1 hash of a namespace
+ * identifier (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function uuid5($ns, $name);
+
+ /**
+ * Creates a UUID from a byte string.
+ *
+ * @param string $bytes A 16-byte string representation of a UUID
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ * @throws InvalidArgumentException if string has not 16 characters
+ */
+ public function fromBytes($bytes);
+
+ /**
+ * Creates a UUID from the string standard representation
+ *
+ * @param string $uuid A string representation of a UUID
+ * @return UuidInterface
+ * @throws InvalidUuidStringException
+ */
+ public function fromString($uuid);
+
+ /**
+ * Creates a `Uuid` from an integer representation
+ *
+ * The integer representation may be a real integer, a string integer, or
+ * an integer representation supported by a configured number converter.
+ *
+ * @param mixed $integer The integer to use when creating a `Uuid` from an
+ * integer; may be of any type understood by the configured number converter
+ * @return UuidInterface
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidUuidStringException
+ */
+ public function fromInteger($integer);
+}
diff --git a/vendor/ramsey/uuid/src/UuidInterface.php b/vendor/ramsey/uuid/src/UuidInterface.php
new file mode 100644
index 0000000..42a3ad7
--- /dev/null
+++ b/vendor/ramsey/uuid/src/UuidInterface.php
@@ -0,0 +1,274 @@
+<?php
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
+ * @link https://packagist.org/packages/ramsey/uuid Packagist
+ * @link https://github.com/ramsey/uuid GitHub
+ */
+
+namespace Ramsey\Uuid;
+
+use DateTime;
+use JsonSerializable;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use Serializable;
+
+/**
+ * UuidInterface defines common functionality for all universally unique
+ * identifiers (UUIDs)
+ */
+interface UuidInterface extends JsonSerializable, Serializable
+{
+ /**
+ * Compares this UUID to the specified UUID.
+ *
+ * The first of two UUIDs is greater than the second if the most
+ * significant field in which the UUIDs differ is greater for the first
+ * UUID.
+ *
+ * * Q. What's the value of being able to sort UUIDs?
+ * * A. Use them as keys in a B-Tree or similar mapping.
+ *
+ * @param UuidInterface $other UUID to which this UUID is compared
+ * @return int -1, 0 or 1 as this UUID is less than, equal to, or greater than `$uuid`
+ */
+ public function compareTo(UuidInterface $other);
+
+ /**
+ * Compares this object to the specified object.
+ *
+ * The result is true if and only if the argument is not null, is a UUID
+ * object, has the same variant, and contains the same value, bit for bit,
+ * as this UUID.
+ *
+ * @param object $other
+ * @return bool True if `$other` is equal to this UUID
+ */
+ public function equals($other);
+
+ /**
+ * Returns the UUID as a 16-byte string (containing the six integer fields
+ * in big-endian byte order).
+ *
+ * @return string
+ */
+ public function getBytes();
+
+ /**
+ * Returns the number converter to use for converting hex values to/from integers.
+ *
+ * @return NumberConverterInterface
+ */
+ public function getNumberConverter();
+
+ /**
+ * Returns the hexadecimal value of the UUID.
+ *
+ * @return string
+ */
+ public function getHex();
+
+ /**
+ * Returns an array of the fields of this UUID, with keys named according
+ * to the RFC 4122 names for the fields.
+ *
+ * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer
+ * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer
+ * * **time_hi_and_version**: The high field of the timestamp multiplexed with
+ * the version number, an unsigned 16-bit integer
+ * * **clock_seq_hi_and_reserved**: The high field of the clock sequence
+ * multiplexed with the variant, an unsigned 8-bit integer
+ * * **clock_seq_low**: The low field of the clock sequence, an unsigned
+ * 8-bit integer
+ * * **node**: The spatially unique node identifier, an unsigned 48-bit
+ * integer
+ *
+ * @return array The UUID fields represented as hexadecimal values
+ */
+ public function getFieldsHex();
+
+ /**
+ * Returns the high field of the clock sequence multiplexed with the variant
+ * (bits 65-72 of the UUID).
+ *
+ * @return string Hexadecimal value of clock_seq_hi_and_reserved
+ */
+ public function getClockSeqHiAndReservedHex();
+
+ /**
+ * Returns the low field of the clock sequence (bits 73-80 of the UUID).
+ *
+ * @return string Hexadecimal value of clock_seq_low
+ */
+ public function getClockSeqLowHex();
+
+ /**
+ * Returns the clock sequence value associated with this UUID.
+ *
+ * @return string Hexadecimal value of clock sequence
+ */
+ public function getClockSequenceHex();
+
+ /**
+ * Returns a PHP `DateTime` object representing the timestamp associated
+ * with this UUID.
+ *
+ * The timestamp value is only meaningful in a time-based UUID, which
+ * has version type 1. If this UUID is not a time-based UUID then
+ * this method throws `UnsupportedOperationException`.
+ *
+ * @return DateTime A PHP DateTime representation of the date
+ * @throws UnsupportedOperationException If this UUID is not a version 1 UUID
+ * @throws UnsatisfiedDependencyException if called in a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ */
+ public function getDateTime();
+
+ /**
+ * Returns the integer value of the UUID, converted to an appropriate number
+ * representation.
+ *
+ * @return mixed Converted representation of the unsigned 128-bit integer value
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ */
+ public function getInteger();
+
+ /**
+ * Returns the least significant 64 bits of this UUID's 128 bit value.
+ *
+ * @return string Hexadecimal value of least significant bits
+ */
+ public function getLeastSignificantBitsHex();
+
+ /**
+ * Returns the most significant 64 bits of this UUID's 128 bit value.
+ *
+ * @return string Hexadecimal value of most significant bits
+ */
+ public function getMostSignificantBitsHex();
+
+ /**
+ * Returns the node value associated with this UUID
+ *
+ * For UUID version 1, the node field consists of an IEEE 802 MAC
+ * address, usually the host address. For systems with multiple IEEE
+ * 802 addresses, any available one can be used. The lowest addressed
+ * octet (octet number 10) contains the global/local bit and the
+ * unicast/multicast bit, and is the first octet of the address
+ * transmitted on an 802.3 LAN.
+ *
+ * For systems with no IEEE address, a randomly or pseudo-randomly
+ * generated value may be used; see RFC 4122, Section 4.5. The
+ * multicast bit must be set in such addresses, in order that they
+ * will never conflict with addresses obtained from network cards.
+ *
+ * For UUID version 3 or 5, the node field is a 48-bit value constructed
+ * from a name as described in RFC 4122, Section 4.3.
+ *
+ * For UUID version 4, the node field is a randomly or pseudo-randomly
+ * generated 48-bit value as described in RFC 4122, Section 4.4.
+ *
+ * @return string Hexadecimal value of node
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.6
+ */
+ public function getNodeHex();
+
+ /**
+ * Returns the high field of the timestamp multiplexed with the version
+ * number (bits 49-64 of the UUID).
+ *
+ * @return string Hexadecimal value of time_hi_and_version
+ */
+ public function getTimeHiAndVersionHex();
+
+ /**
+ * Returns the low field of the timestamp (the first 32 bits of the UUID).
+ *
+ * @return string Hexadecimal value of time_low
+ */
+ public function getTimeLowHex();
+
+ /**
+ * Returns the middle field of the timestamp (bits 33-48 of the UUID).
+ *
+ * @return string Hexadecimal value of time_mid
+ */
+ public function getTimeMidHex();
+
+ /**
+ * Returns the timestamp value associated with this UUID.
+ *
+ * The 60 bit timestamp value is constructed from the time_low,
+ * time_mid, and time_hi fields of this UUID. The resulting
+ * timestamp is measured in 100-nanosecond units since midnight,
+ * October 15, 1582 UTC.
+ *
+ * The timestamp value is only meaningful in a time-based UUID, which
+ * has version type 1. If this UUID is not a time-based UUID then
+ * this method throws UnsupportedOperationException.
+ *
+ * @return string Hexadecimal value of the timestamp
+ * @throws UnsupportedOperationException If this UUID is not a version 1 UUID
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.4
+ */
+ public function getTimestampHex();
+
+ /**
+ * Returns the string representation of the UUID as a URN.
+ *
+ * @return string
+ * @link http://en.wikipedia.org/wiki/Uniform_Resource_Name
+ */
+ public function getUrn();
+
+ /**
+ * Returns the variant number associated with this UUID.
+ *
+ * The variant number describes the layout of the UUID. The variant
+ * number has the following meaning:
+ *
+ * * 0 - Reserved for NCS backward compatibility
+ * * 2 - The RFC 4122 variant (used by this class)
+ * * 6 - Reserved, Microsoft Corporation backward compatibility
+ * * 7 - Reserved for future definition
+ *
+ * @return int
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+ */
+ public function getVariant();
+
+ /**
+ * Returns the version number associated with this UUID.
+ *
+ * The version number describes how this UUID was generated and has the
+ * following meaning:
+ *
+ * * 1 - Time-based UUID
+ * * 2 - DCE security UUID
+ * * 3 - Name-based UUID hashed with MD5
+ * * 4 - Randomly generated UUID
+ * * 5 - Name-based UUID hashed with SHA-1
+ *
+ * Returns null if this UUID is not an RFC 4122 variant, since version
+ * is only meaningful for this variant.
+ *
+ * @return int|null
+ * @link http://tools.ietf.org/html/rfc4122#section-4.1.3
+ */
+ public function getVersion();
+
+ /**
+ * Converts this UUID into a string representation.
+ *
+ * @return string
+ */
+ public function toString();
+}
diff --git a/vendor/ramsey/uuid/src/functions.php b/vendor/ramsey/uuid/src/functions.php
new file mode 100644
index 0000000..b5db341
--- /dev/null
+++ b/vendor/ramsey/uuid/src/functions.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+namespace Ramsey\Uuid;
+
+use Exception;
+use InvalidArgumentException;
+use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+
+/**
+ * Generate a version 1 UUID from a host ID, sequence number, and the current time.
+ *
+ * @param int|string|null $node A 48-bit number representing the hardware address
+ * This number may be represented as an integer or a hexadecimal string.
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that
+ * could arise when the clock is set backwards in time or if the node ID
+ * changes.
+ * @return string
+ * @throws UnsatisfiedDependencyException if called on a 32-bit system and
+ * `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception if it was not possible to gather sufficient entropy
+ */
+function v1($node = null, $clockSeq = null)
+{
+ return Uuid::uuid1($node, $clockSeq)->toString();
+}
+
+/**
+ * Generate a version 3 UUID based on the MD5 hash of a namespace identifier
+ * (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return string
+ * @throws InvalidUuidStringException
+ */
+function v3($ns, $name)
+{
+ return Uuid::uuid3($ns, $name)->toString();
+}
+
+/**
+ * Generate a version 4 (random) UUID.
+ *
+ * @return string
+ * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+ * @throws InvalidArgumentException
+ * @throws Exception
+ */
+function v4()
+{
+ return Uuid::uuid4()->toString();
+}
+
+/**
+ * Generate a version 5 UUID based on the SHA-1 hash of a namespace
+ * identifier (which is a UUID) and a name (which is a string).
+ *
+ * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID
+ * @param string $name The name to create a UUID for
+ * @return string
+ * @throws InvalidUuidStringException
+ */
+function v5($ns, $name)
+{
+ return Uuid::uuid5($ns, $name)->toString();
+}
diff --git a/vendor/react/cache/LICENSE b/vendor/react/cache/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/cache/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/cache/composer.json b/vendor/react/cache/composer.json
new file mode 100644
index 0000000..ad0d9fe
--- /dev/null
+++ b/vendor/react/cache/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "react/cache",
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": ["cache", "caching", "promise", "ReactPHP"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "autoload": {
+ "psr-4": { "React\\Cache\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\Cache\\": "tests/" }
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/react/cache/src/ArrayCache.php b/vendor/react/cache/src/ArrayCache.php
new file mode 100644
index 0000000..81f25ef
--- /dev/null
+++ b/vendor/react/cache/src/ArrayCache.php
@@ -0,0 +1,181 @@
+<?php
+
+namespace React\Cache;
+
+use React\Promise;
+use React\Promise\PromiseInterface;
+
+class ArrayCache implements CacheInterface
+{
+ private $limit;
+ private $data = array();
+ private $expires = array();
+ private $supportsHighResolution;
+
+ /**
+ * The `ArrayCache` provides an in-memory implementation of the [`CacheInterface`](#cacheinterface).
+ *
+ * ```php
+ * $cache = new ArrayCache();
+ *
+ * $cache->set('foo', 'bar');
+ * ```
+ *
+ * Its constructor accepts an optional `?int $limit` parameter to limit the
+ * maximum number of entries to store in the LRU cache. If you add more
+ * entries to this instance, it will automatically take care of removing
+ * the one that was least recently used (LRU).
+ *
+ * For example, this snippet will overwrite the first value and only store
+ * the last two entries:
+ *
+ * ```php
+ * $cache = new ArrayCache(2);
+ *
+ * $cache->set('foo', '1');
+ * $cache->set('bar', '2');
+ * $cache->set('baz', '3');
+ * ```
+ *
+ * This cache implementation is known to rely on wall-clock time to schedule
+ * future cache expiration times when using any version before PHP 7.3,
+ * because a monotonic time source is only available as of PHP 7.3 (`hrtime()`).
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you store a cache item with a TTL of 30s on PHP < 7.3
+ * and then adjust your system time forward by 20s, the cache item may
+ * expire in 10s. See also [`set()`](#set) for more details.
+ *
+ * @param int|null $limit maximum number of entries to store in the LRU cache
+ */
+ public function __construct($limit = null)
+ {
+ $this->limit = $limit;
+
+ // prefer high-resolution timer, available as of PHP 7.3+
+ $this->supportsHighResolution = \function_exists('hrtime');
+ }
+
+ public function get($key, $default = null)
+ {
+ // delete key if it is already expired => below will detect this as a cache miss
+ if (isset($this->expires[$key]) && $this->now() - $this->expires[$key] > 0) {
+ unset($this->data[$key], $this->expires[$key]);
+ }
+
+ if (!\array_key_exists($key, $this->data)) {
+ return Promise\resolve($default);
+ }
+
+ // remove and append to end of array to keep track of LRU info
+ $value = $this->data[$key];
+ unset($this->data[$key]);
+ $this->data[$key] = $value;
+
+ return Promise\resolve($value);
+ }
+
+ public function set($key, $value, $ttl = null)
+ {
+ // unset before setting to ensure this entry will be added to end of array (LRU info)
+ unset($this->data[$key]);
+ $this->data[$key] = $value;
+
+ // sort expiration times if TTL is given (first will expire first)
+ unset($this->expires[$key]);
+ if ($ttl !== null) {
+ $this->expires[$key] = $this->now() + $ttl;
+ \asort($this->expires);
+ }
+
+ // ensure size limit is not exceeded or remove first entry from array
+ if ($this->limit !== null && \count($this->data) > $this->limit) {
+ // first try to check if there's any expired entry
+ // expiration times are sorted, so we can simply look at the first one
+ \reset($this->expires);
+ $key = \key($this->expires);
+
+ // check to see if the first in the list of expiring keys is already expired
+ // if the first key is not expired, we have to overwrite by using LRU info
+ if ($key === null || $this->now() - $this->expires[$key] < 0) {
+ \reset($this->data);
+ $key = \key($this->data);
+ }
+ unset($this->data[$key], $this->expires[$key]);
+ }
+
+ return Promise\resolve(true);
+ }
+
+ public function delete($key)
+ {
+ unset($this->data[$key], $this->expires[$key]);
+
+ return Promise\resolve(true);
+ }
+
+ public function getMultiple(array $keys, $default = null)
+ {
+ $values = array();
+
+ foreach ($keys as $key) {
+ $values[$key] = $this->get($key, $default);
+ }
+
+ return Promise\all($values);
+ }
+
+ public function setMultiple(array $values, $ttl = null)
+ {
+ foreach ($values as $key => $value) {
+ $this->set($key, $value, $ttl);
+ }
+
+ return Promise\resolve(true);
+ }
+
+ public function deleteMultiple(array $keys)
+ {
+ foreach ($keys as $key) {
+ unset($this->data[$key], $this->expires[$key]);
+ }
+
+ return Promise\resolve(true);
+ }
+
+ public function clear()
+ {
+ $this->data = array();
+ $this->expires = array();
+
+ return Promise\resolve(true);
+ }
+
+ public function has($key)
+ {
+ // delete key if it is already expired
+ if (isset($this->expires[$key]) && $this->now() - $this->expires[$key] > 0) {
+ unset($this->data[$key], $this->expires[$key]);
+ }
+
+ if (!\array_key_exists($key, $this->data)) {
+ return Promise\resolve(false);
+ }
+
+ // remove and append to end of array to keep track of LRU info
+ $value = $this->data[$key];
+ unset($this->data[$key]);
+ $this->data[$key] = $value;
+
+ return Promise\resolve(true);
+ }
+
+ /**
+ * @return float
+ */
+ private function now()
+ {
+ return $this->supportsHighResolution ? \hrtime(true) * 1e-9 : \microtime(true);
+ }
+}
diff --git a/vendor/react/cache/src/CacheInterface.php b/vendor/react/cache/src/CacheInterface.php
new file mode 100644
index 0000000..8e51c19
--- /dev/null
+++ b/vendor/react/cache/src/CacheInterface.php
@@ -0,0 +1,194 @@
+<?php
+
+namespace React\Cache;
+
+use React\Promise\PromiseInterface;
+
+interface CacheInterface
+{
+ /**
+ * Retrieves an item from the cache.
+ *
+ * This method will resolve with the cached value on success or with the
+ * given `$default` value when no item can be found or when an error occurs.
+ * Similarly, an expired cache item (once the time-to-live is expired) is
+ * considered a cache miss.
+ *
+ * ```php
+ * $cache
+ * ->get('foo')
+ * ->then('var_dump');
+ * ```
+ *
+ * This example fetches the value of the key `foo` and passes it to the
+ * `var_dump` function. You can use any of the composition provided by
+ * [promises](https://github.com/reactphp/promise).
+ *
+ * @param string $key
+ * @param mixed $default Default value to return for cache miss or null if not given.
+ * @return PromiseInterface<mixed>
+ */
+ public function get($key, $default = null);
+
+ /**
+ * Stores an item in the cache.
+ *
+ * This method will resolve with `true` on success or `false` when an error
+ * occurs. If the cache implementation has to go over the network to store
+ * it, it may take a while.
+ *
+ * The optional `$ttl` parameter sets the maximum time-to-live in seconds
+ * for this cache item. If this parameter is omitted (or `null`), the item
+ * will stay in the cache for as long as the underlying implementation
+ * supports. Trying to access an expired cache item results in a cache miss,
+ * see also [`get()`](#get).
+ *
+ * ```php
+ * $cache->set('foo', 'bar', 60);
+ * ```
+ *
+ * This example eventually sets the value of the key `foo` to `bar`. If it
+ * already exists, it is overridden.
+ *
+ * This interface does not enforce any particular TTL resolution, so special
+ * care may have to be taken if you rely on very high precision with
+ * millisecond accuracy or below. Cache implementations SHOULD work on a
+ * best effort basis and SHOULD provide at least second accuracy unless
+ * otherwise noted. Many existing cache implementations are known to provide
+ * microsecond or millisecond accuracy, but it's generally not recommended
+ * to rely on this high precision.
+ *
+ * This interface suggests that cache implementations SHOULD use a monotonic
+ * time source if available. Given that a monotonic time source is only
+ * available as of PHP 7.3 by default, cache implementations MAY fall back
+ * to using wall-clock time.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you store a cache item with a TTL of 30s and then
+ * adjust your system time forward by 20s, the cache item SHOULD still
+ * expire in 30s.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param ?float $ttl
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function set($key, $value, $ttl = null);
+
+ /**
+ * Deletes an item from the cache.
+ *
+ * This method will resolve with `true` on success or `false` when an error
+ * occurs. When no item for `$key` is found in the cache, it also resolves
+ * to `true`. If the cache implementation has to go over the network to
+ * delete it, it may take a while.
+ *
+ * ```php
+ * $cache->delete('foo');
+ * ```
+ *
+ * This example eventually deletes the key `foo` from the cache. As with
+ * `set()`, this may not happen instantly and a promise is returned to
+ * provide guarantees whether or not the item has been removed from cache.
+ *
+ * @param string $key
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function delete($key);
+
+ /**
+ * Retrieves multiple cache items by their unique keys.
+ *
+ * This method will resolve with an array of cached values on success or with the
+ * given `$default` value when an item can not be found or when an error occurs.
+ * Similarly, an expired cache item (once the time-to-live is expired) is
+ * considered a cache miss.
+ *
+ * ```php
+ * $cache->getMultiple(array('name', 'age'))->then(function (array $values) {
+ * $name = $values['name'] ?? 'User';
+ * $age = $values['age'] ?? 'n/a';
+ *
+ * echo $name . ' is ' . $age . PHP_EOL;
+ * });
+ * ```
+ *
+ * This example fetches the cache items for the `name` and `age` keys and
+ * prints some example output. You can use any of the composition provided
+ * by [promises](https://github.com/reactphp/promise).
+ *
+ * @param string[] $keys A list of keys that can obtained in a single operation.
+ * @param mixed $default Default value to return for keys that do not exist.
+ * @return PromiseInterface<array> Returns a promise which resolves to an `array` of cached values
+ */
+ public function getMultiple(array $keys, $default = null);
+
+ /**
+ * Persists a set of key => value pairs in the cache, with an optional TTL.
+ *
+ * This method will resolve with `true` on success or `false` when an error
+ * occurs. If the cache implementation has to go over the network to store
+ * it, it may take a while.
+ *
+ * The optional `$ttl` parameter sets the maximum time-to-live in seconds
+ * for these cache items. If this parameter is omitted (or `null`), these items
+ * will stay in the cache for as long as the underlying implementation
+ * supports. Trying to access an expired cache items results in a cache miss,
+ * see also [`get()`](#get).
+ *
+ * ```php
+ * $cache->setMultiple(array('foo' => 1, 'bar' => 2), 60);
+ * ```
+ *
+ * This example eventually sets the list of values - the key `foo` to 1 value
+ * and the key `bar` to 2. If some of the keys already exist, they are overridden.
+ *
+ * @param array $values A list of key => value pairs for a multiple-set operation.
+ * @param ?float $ttl Optional. The TTL value of this item.
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function setMultiple(array $values, $ttl = null);
+
+ /**
+ * Deletes multiple cache items in a single operation.
+ *
+ * @param string[] $keys A list of string-based keys to be deleted.
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function deleteMultiple(array $keys);
+
+ /**
+ * Wipes clean the entire cache.
+ *
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function clear();
+
+ /**
+ * Determines whether an item is present in the cache.
+ *
+ * This method will resolve with `true` on success or `false` when no item can be found
+ * or when an error occurs. Similarly, an expired cache item (once the time-to-live
+ * is expired) is considered a cache miss.
+ *
+ * ```php
+ * $cache
+ * ->has('foo')
+ * ->then('var_dump');
+ * ```
+ *
+ * This example checks if the value of the key `foo` is set in the cache and passes
+ * the result to the `var_dump` function. You can use any of the composition provided by
+ * [promises](https://github.com/reactphp/promise).
+ *
+ * NOTE: It is recommended that has() is only to be used for cache warming type purposes
+ * and not to be used within your live applications operations for get/set, as this method
+ * is subject to a race condition where your has() will return true and immediately after,
+ * another script can remove it making the state of your app out of date.
+ *
+ * @param string $key The cache item key.
+ * @return PromiseInterface<bool> Returns a promise which resolves to `true` on success or `false` on error
+ */
+ public function has($key);
+}
diff --git a/vendor/react/child-process/LICENSE b/vendor/react/child-process/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/child-process/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/child-process/composer.json b/vendor/react/child-process/composer.json
new file mode 100644
index 0000000..32aa713
--- /dev/null
+++ b/vendor/react/child-process/composer.json
@@ -0,0 +1,45 @@
+{
+ "name": "react/child-process",
+ "description": "Event-driven library for executing child processes with ReactPHP.",
+ "keywords": ["process", "event-driven", "ReactPHP"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "react/event-loop": "^1.2",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/socket": "^1.8",
+ "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
+ },
+ "autoload": {
+ "psr-4": { "React\\ChildProcess\\": "src" }
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\ChildProcess\\": "tests" }
+ }
+}
diff --git a/vendor/react/child-process/src/Process.php b/vendor/react/child-process/src/Process.php
new file mode 100644
index 0000000..2a275e9
--- /dev/null
+++ b/vendor/react/child-process/src/Process.php
@@ -0,0 +1,567 @@
+<?php
+
+namespace React\ChildProcess;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Stream\ReadableResourceStream;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\WritableResourceStream;
+use React\Stream\WritableStreamInterface;
+use React\Stream\DuplexResourceStream;
+use React\Stream\DuplexStreamInterface;
+
+/**
+ * Process component.
+ *
+ * This class borrows logic from Symfony's Process component for ensuring
+ * compatibility when PHP is compiled with the --enable-sigchild option.
+ *
+ * This class also implements the `EventEmitterInterface`
+ * which allows you to react to certain events:
+ *
+ * exit event:
+ * The `exit` event will be emitted whenever the process is no longer running.
+ * Event listeners will receive the exit code and termination signal as two
+ * arguments:
+ *
+ * ```php
+ * $process = new Process('sleep 10');
+ * $process->start();
+ *
+ * $process->on('exit', function ($code, $term) {
+ * if ($term === null) {
+ * echo 'exit with code ' . $code . PHP_EOL;
+ * } else {
+ * echo 'terminated with signal ' . $term . PHP_EOL;
+ * }
+ * });
+ * ```
+ *
+ * Note that `$code` is `null` if the process has terminated, but the exit
+ * code could not be determined (for example
+ * [sigchild compatibility](#sigchild-compatibility) was disabled).
+ * Similarly, `$term` is `null` unless the process has terminated in response to
+ * an uncaught signal sent to it.
+ * This is not a limitation of this project, but actual how exit codes and signals
+ * are exposed on POSIX systems, for more details see also
+ * [here](https://unix.stackexchange.com/questions/99112/default-exit-code-when-process-is-terminated).
+ *
+ * It's also worth noting that process termination depends on all file descriptors
+ * being closed beforehand.
+ * This means that all [process pipes](#stream-properties) will emit a `close`
+ * event before the `exit` event and that no more `data` events will arrive after
+ * the `exit` event.
+ * Accordingly, if either of these pipes is in a paused state (`pause()` method
+ * or internally due to a `pipe()` call), this detection may not trigger.
+ */
+class Process extends EventEmitter
+{
+ /**
+ * @var WritableStreamInterface|null|DuplexStreamInterface|ReadableStreamInterface
+ */
+ public $stdin;
+
+ /**
+ * @var ReadableStreamInterface|null|DuplexStreamInterface|WritableStreamInterface
+ */
+ public $stdout;
+
+ /**
+ * @var ReadableStreamInterface|null|DuplexStreamInterface|WritableStreamInterface
+ */
+ public $stderr;
+
+ /**
+ * Array with all process pipes (once started)
+ *
+ * Unless explicitly configured otherwise during construction, the following
+ * standard I/O pipes will be assigned by default:
+ * - 0: STDIN (`WritableStreamInterface`)
+ * - 1: STDOUT (`ReadableStreamInterface`)
+ * - 2: STDERR (`ReadableStreamInterface`)
+ *
+ * @var array<ReadableStreamInterface|WritableStreamInterface|DuplexStreamInterface>
+ */
+ public $pipes = array();
+
+ private $cmd;
+ private $cwd;
+ private $env;
+ private $fds;
+
+ private $enhanceSigchildCompatibility;
+ private $sigchildPipe;
+
+ private $process;
+ private $status;
+ private $exitCode;
+ private $fallbackExitCode;
+ private $stopSignal;
+ private $termSignal;
+
+ private static $sigchild;
+
+ /**
+ * Constructor.
+ *
+ * @param string $cmd Command line to run
+ * @param null|string $cwd Current working directory or null to inherit
+ * @param null|array $env Environment variables or null to inherit
+ * @param null|array $fds File descriptors to allocate for this process (or null = default STDIO streams)
+ * @throws \LogicException On windows or when proc_open() is not installed
+ */
+ public function __construct($cmd, $cwd = null, array $env = null, array $fds = null)
+ {
+ if (!\function_exists('proc_open')) {
+ throw new \LogicException('The Process class relies on proc_open(), which is not available on your PHP installation.');
+ }
+
+ $this->cmd = $cmd;
+ $this->cwd = $cwd;
+
+ if (null !== $env) {
+ $this->env = array();
+ foreach ($env as $key => $value) {
+ $this->env[(binary) $key] = (binary) $value;
+ }
+ }
+
+ if ($fds === null) {
+ $fds = array(
+ array('pipe', 'r'), // stdin
+ array('pipe', 'w'), // stdout
+ array('pipe', 'w'), // stderr
+ );
+ }
+
+ if (\DIRECTORY_SEPARATOR === '\\') {
+ foreach ($fds as $fd) {
+ if (isset($fd[0]) && $fd[0] === 'pipe') {
+ throw new \LogicException('Process pipes are not supported on Windows due to their blocking nature on Windows');
+ }
+ }
+ }
+
+ $this->fds = $fds;
+ $this->enhanceSigchildCompatibility = self::isSigchildEnabled();
+ }
+
+ /**
+ * Start the process.
+ *
+ * After the process is started, the standard I/O streams will be constructed
+ * and available via public properties.
+ *
+ * This method takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this process. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param ?LoopInterface $loop Loop interface for stream construction
+ * @param float $interval Interval to periodically monitor process state (seconds)
+ * @throws \RuntimeException If the process is already running or fails to start
+ */
+ public function start(LoopInterface $loop = null, $interval = 0.1)
+ {
+ if ($this->isRunning()) {
+ throw new \RuntimeException('Process is already running');
+ }
+
+ $loop = $loop ?: Loop::get();
+ $cmd = $this->cmd;
+ $fdSpec = $this->fds;
+ $sigchild = null;
+
+ // Read exit code through fourth pipe to work around --enable-sigchild
+ if ($this->enhanceSigchildCompatibility) {
+ $fdSpec[] = array('pipe', 'w');
+ \end($fdSpec);
+ $sigchild = \key($fdSpec);
+
+ // make sure this is fourth or higher (do not mess with STDIO)
+ if ($sigchild < 3) {
+ $fdSpec[3] = $fdSpec[$sigchild];
+ unset($fdSpec[$sigchild]);
+ $sigchild = 3;
+ }
+
+ $cmd = \sprintf('(%s) ' . $sigchild . '>/dev/null; code=$?; echo $code >&' . $sigchild . '; exit $code', $cmd);
+ }
+
+ // on Windows, we do not launch the given command line in a shell (cmd.exe) by default and omit any error dialogs
+ // the cmd.exe shell can explicitly be given as part of the command as detailed in both documentation and tests
+ $options = array();
+ if (\DIRECTORY_SEPARATOR === '\\') {
+ $options['bypass_shell'] = true;
+ $options['suppress_errors'] = true;
+ }
+
+ $this->process = @\proc_open($cmd, $fdSpec, $pipes, $this->cwd, $this->env, $options);
+
+ if (!\is_resource($this->process)) {
+ $error = \error_get_last();
+ throw new \RuntimeException('Unable to launch a new process: ' . $error['message']);
+ }
+
+ // count open process pipes and await close event for each to drain buffers before detecting exit
+ $that = $this;
+ $closeCount = 0;
+ $streamCloseHandler = function () use (&$closeCount, $loop, $interval, $that) {
+ $closeCount--;
+
+ if ($closeCount > 0) {
+ return;
+ }
+
+ // process already closed => report immediately
+ if (!$that->isRunning()) {
+ $that->close();
+ $that->emit('exit', array($that->getExitCode(), $that->getTermSignal()));
+ return;
+ }
+
+ // close not detected immediately => check regularly
+ $loop->addPeriodicTimer($interval, function ($timer) use ($that, $loop) {
+ if (!$that->isRunning()) {
+ $loop->cancelTimer($timer);
+ $that->close();
+ $that->emit('exit', array($that->getExitCode(), $that->getTermSignal()));
+ }
+ });
+ };
+
+ if ($sigchild !== null) {
+ $this->sigchildPipe = $pipes[$sigchild];
+ unset($pipes[$sigchild]);
+ }
+
+ foreach ($pipes as $n => $fd) {
+ // use open mode from stream meta data or fall back to pipe open mode for legacy HHVM
+ $meta = \stream_get_meta_data($fd);
+ $mode = $meta['mode'] === '' ? ($this->fds[$n][1] === 'r' ? 'w' : 'r') : $meta['mode'];
+
+ if ($mode === 'r+') {
+ $stream = new DuplexResourceStream($fd, $loop);
+ $stream->on('close', $streamCloseHandler);
+ $closeCount++;
+ } elseif ($mode === 'w') {
+ $stream = new WritableResourceStream($fd, $loop);
+ } else {
+ $stream = new ReadableResourceStream($fd, $loop);
+ $stream->on('close', $streamCloseHandler);
+ $closeCount++;
+ }
+ $this->pipes[$n] = $stream;
+ }
+
+ $this->stdin = isset($this->pipes[0]) ? $this->pipes[0] : null;
+ $this->stdout = isset($this->pipes[1]) ? $this->pipes[1] : null;
+ $this->stderr = isset($this->pipes[2]) ? $this->pipes[2] : null;
+
+ // immediately start checking for process exit when started without any I/O pipes
+ if (!$closeCount) {
+ $streamCloseHandler();
+ }
+ }
+
+ /**
+ * Close the process.
+ *
+ * This method should only be invoked via the periodic timer that monitors
+ * the process state.
+ */
+ public function close()
+ {
+ if ($this->process === null) {
+ return;
+ }
+
+ foreach ($this->pipes as $pipe) {
+ $pipe->close();
+ }
+
+ if ($this->enhanceSigchildCompatibility) {
+ $this->pollExitCodePipe();
+ $this->closeExitCodePipe();
+ }
+
+ $exitCode = \proc_close($this->process);
+ $this->process = null;
+
+ if ($this->exitCode === null && $exitCode !== -1) {
+ $this->exitCode = $exitCode;
+ }
+
+ if ($this->exitCode === null && $this->status['exitcode'] !== -1) {
+ $this->exitCode = $this->status['exitcode'];
+ }
+
+ if ($this->exitCode === null && $this->fallbackExitCode !== null) {
+ $this->exitCode = $this->fallbackExitCode;
+ $this->fallbackExitCode = null;
+ }
+ }
+
+ /**
+ * Terminate the process with an optional signal.
+ *
+ * @param int $signal Optional signal (default: SIGTERM)
+ * @return bool Whether the signal was sent successfully
+ */
+ public function terminate($signal = null)
+ {
+ if ($this->process === null) {
+ return false;
+ }
+
+ if ($signal !== null) {
+ return \proc_terminate($this->process, $signal);
+ }
+
+ return \proc_terminate($this->process);
+ }
+
+ /**
+ * Get the command string used to launch the process.
+ *
+ * @return string
+ */
+ public function getCommand()
+ {
+ return $this->cmd;
+ }
+
+ /**
+ * Get the exit code returned by the process.
+ *
+ * This value is only meaningful if isRunning() has returned false. Null
+ * will be returned if the process is still running.
+ *
+ * Null may also be returned if the process has terminated, but the exit
+ * code could not be determined (e.g. sigchild compatibility was disabled).
+ *
+ * @return int|null
+ */
+ public function getExitCode()
+ {
+ return $this->exitCode;
+ }
+
+ /**
+ * Get the process ID.
+ *
+ * @return int|null
+ */
+ public function getPid()
+ {
+ $status = $this->getCachedStatus();
+
+ return $status !== null ? $status['pid'] : null;
+ }
+
+ /**
+ * Get the signal that caused the process to stop its execution.
+ *
+ * This value is only meaningful if isStopped() has returned true. Null will
+ * be returned if the process was never stopped.
+ *
+ * @return int|null
+ */
+ public function getStopSignal()
+ {
+ return $this->stopSignal;
+ }
+
+ /**
+ * Get the signal that caused the process to terminate its execution.
+ *
+ * This value is only meaningful if isTerminated() has returned true. Null
+ * will be returned if the process was never terminated.
+ *
+ * @return int|null
+ */
+ public function getTermSignal()
+ {
+ return $this->termSignal;
+ }
+
+ /**
+ * Return whether the process is still running.
+ *
+ * @return bool
+ */
+ public function isRunning()
+ {
+ if ($this->process === null) {
+ return false;
+ }
+
+ $status = $this->getFreshStatus();
+
+ return $status !== null ? $status['running'] : false;
+ }
+
+ /**
+ * Return whether the process has been stopped by a signal.
+ *
+ * @return bool
+ */
+ public function isStopped()
+ {
+ $status = $this->getFreshStatus();
+
+ return $status !== null ? $status['stopped'] : false;
+ }
+
+ /**
+ * Return whether the process has been terminated by an uncaught signal.
+ *
+ * @return bool
+ */
+ public function isTerminated()
+ {
+ $status = $this->getFreshStatus();
+
+ return $status !== null ? $status['signaled'] : false;
+ }
+
+ /**
+ * Return whether PHP has been compiled with the '--enable-sigchild' option.
+ *
+ * @see \Symfony\Component\Process\Process::isSigchildEnabled()
+ * @return bool
+ */
+ public final static function isSigchildEnabled()
+ {
+ if (null !== self::$sigchild) {
+ return self::$sigchild;
+ }
+
+ if (!\function_exists('phpinfo')) {
+ return self::$sigchild = false; // @codeCoverageIgnore
+ }
+
+ \ob_start();
+ \phpinfo(INFO_GENERAL);
+
+ return self::$sigchild = false !== \strpos(\ob_get_clean(), '--enable-sigchild');
+ }
+
+ /**
+ * Enable or disable sigchild compatibility mode.
+ *
+ * Sigchild compatibility mode is required to get the exit code and
+ * determine the success of a process when PHP has been compiled with
+ * the --enable-sigchild option.
+ *
+ * @param bool $sigchild
+ * @return void
+ */
+ public final static function setSigchildEnabled($sigchild)
+ {
+ self::$sigchild = (bool) $sigchild;
+ }
+
+ /**
+ * Check the fourth pipe for an exit code.
+ *
+ * This should only be used if --enable-sigchild compatibility was enabled.
+ */
+ private function pollExitCodePipe()
+ {
+ if ($this->sigchildPipe === null) {
+ return;
+ }
+
+ $r = array($this->sigchildPipe);
+ $w = $e = null;
+
+ $n = @\stream_select($r, $w, $e, 0);
+
+ if (1 !== $n) {
+ return;
+ }
+
+ $data = \fread($r[0], 8192);
+
+ if (\strlen($data) > 0) {
+ $this->fallbackExitCode = (int) $data;
+ }
+ }
+
+ /**
+ * Close the fourth pipe used to relay an exit code.
+ *
+ * This should only be used if --enable-sigchild compatibility was enabled.
+ */
+ private function closeExitCodePipe()
+ {
+ if ($this->sigchildPipe === null) {
+ return;
+ }
+
+ \fclose($this->sigchildPipe);
+ $this->sigchildPipe = null;
+ }
+
+ /**
+ * Return the cached process status.
+ *
+ * @return array
+ */
+ private function getCachedStatus()
+ {
+ if ($this->status === null) {
+ $this->updateStatus();
+ }
+
+ return $this->status;
+ }
+
+ /**
+ * Return the updated process status.
+ *
+ * @return array
+ */
+ private function getFreshStatus()
+ {
+ $this->updateStatus();
+
+ return $this->status;
+ }
+
+ /**
+ * Update the process status, stop/term signals, and exit code.
+ *
+ * Stop/term signals are only updated if the process is currently stopped or
+ * signaled, respectively. Otherwise, signal values will remain as-is so the
+ * corresponding getter methods may be used at a later point in time.
+ */
+ private function updateStatus()
+ {
+ if ($this->process === null) {
+ return;
+ }
+
+ $this->status = \proc_get_status($this->process);
+
+ if ($this->status === false) {
+ throw new \UnexpectedValueException('proc_get_status() failed');
+ }
+
+ if ($this->status['stopped']) {
+ $this->stopSignal = $this->status['stopsig'];
+ }
+
+ if ($this->status['signaled']) {
+ $this->termSignal = $this->status['termsig'];
+ }
+
+ if (!$this->status['running'] && -1 !== $this->status['exitcode']) {
+ $this->exitCode = $this->status['exitcode'];
+ }
+ }
+}
diff --git a/vendor/react/datagram/LICENSE b/vendor/react/datagram/LICENSE
new file mode 100644
index 0000000..61974a9
--- /dev/null
+++ b/vendor/react/datagram/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden
+
+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/react/datagram/composer.json b/vendor/react/datagram/composer.json
new file mode 100644
index 0000000..c5b5934
--- /dev/null
+++ b/vendor/react/datagram/composer.json
@@ -0,0 +1,50 @@
+{
+ "name": "react/datagram",
+ "description": "Event-driven UDP datagram socket client and server for ReactPHP",
+ "keywords": ["udp", "datagram", "dgram", "socket", "client", "server", "ReactPHP", "async"],
+ "homepage": "https://github.com/reactphp/datagram",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "React\\Datagram\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Tests\\Datagram\\": "tests"
+ }
+ },
+ "require": {
+ "php": ">=5.3",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "react/event-loop": "^1.2",
+ "react/dns": "^1.7",
+ "react/promise": "~2.1|~1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "~1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/react/datagram/src/Buffer.php b/vendor/react/datagram/src/Buffer.php
new file mode 100644
index 0000000..e5aa2f6
--- /dev/null
+++ b/vendor/react/datagram/src/Buffer.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace React\Datagram;
+
+use Evenement\EventEmitter;
+use React\EventLoop\LoopInterface;
+use \Exception;
+
+class Buffer extends EventEmitter
+{
+ protected $loop;
+ protected $socket;
+
+ private $listening = false;
+ private $outgoing = array();
+ private $writable = true;
+
+ public function __construct(LoopInterface $loop, $socket)
+ {
+ $this->loop = $loop;
+ $this->socket = $socket;
+ }
+
+ public function send($data, $remoteAddress = null)
+ {
+ if ($this->writable === false) {
+ return;
+ }
+
+ $this->outgoing []= array($data, $remoteAddress);
+
+ if (!$this->listening) {
+ $this->handleResume();
+ $this->listening = true;
+ }
+ }
+
+ public function onWritable()
+ {
+ list($data, $remoteAddress) = \array_shift($this->outgoing);
+
+ try {
+ $this->handleWrite($data, $remoteAddress);
+ }
+ catch (Exception $e) {
+ $this->emit('error', array($e, $this));
+ }
+
+ if (!$this->outgoing) {
+ if ($this->listening) {
+ $this->handlePause();
+ $this->listening = false;
+ }
+
+ if (!$this->writable) {
+ $this->close();
+ }
+ }
+ }
+
+ public function close()
+ {
+ if ($this->socket === false) {
+ return;
+ }
+
+ $this->emit('close', array($this));
+
+ if ($this->listening) {
+ $this->handlePause();
+ $this->listening = false;
+ }
+
+ $this->writable = false;
+ $this->socket = false;
+ $this->outgoing = array();
+ $this->removeAllListeners();
+ }
+
+ public function end()
+ {
+ $this->writable = false;
+
+ if (!$this->outgoing) {
+ $this->close();
+ }
+ }
+
+ protected function handlePause()
+ {
+ $this->loop->removeWriteStream($this->socket);
+ }
+
+ protected function handleResume()
+ {
+ $this->loop->addWriteStream($this->socket, array($this, 'onWritable'));
+ }
+
+ protected function handleWrite($data, $remoteAddress)
+ {
+ if ($remoteAddress === null) {
+ // do not use fwrite() as it obeys the stream buffer size and
+ // packets are not to be split at 8kb
+ $ret = @\stream_socket_sendto($this->socket, $data);
+ } else {
+ $ret = @\stream_socket_sendto($this->socket, $data, 0, $remoteAddress);
+ }
+
+ if ($ret < 0 || $ret === false) {
+ $error = \error_get_last();
+ throw new Exception('Unable to send packet: ' . \trim($error['message']));
+ }
+ }
+}
diff --git a/vendor/react/datagram/src/Factory.php b/vendor/react/datagram/src/Factory.php
new file mode 100644
index 0000000..add2569
--- /dev/null
+++ b/vendor/react/datagram/src/Factory.php
@@ -0,0 +1,149 @@
+<?php
+
+namespace React\Datagram;
+
+use React\Datagram\Socket;
+use React\Dns\Config\Config as DnsConfig;
+use React\Dns\Resolver\Factory as DnsFactory;
+use React\Dns\Resolver\ResolverInterface;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+use \Exception;
+
+class Factory
+{
+ protected $loop;
+ protected $resolver;
+
+ /**
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param ?LoopInterface $loop
+ * @param ?ResolverInterface $resolver Resolver instance to use. Will otherwise
+ * try to load the system default DNS config or fall back to using
+ * Google's public DNS 8.8.8.8
+ */
+ public function __construct(LoopInterface $loop = null, ResolverInterface $resolver = null)
+ {
+ $loop = $loop ?: Loop::get();
+ if ($resolver === null) {
+ // try to load nameservers from system config or default to Google's public DNS
+ $config = DnsConfig::loadSystemConfigBlocking();
+ if (!$config->nameservers) {
+ $config->nameservers[] = '8.8.8.8'; // @codeCoverageIgnore
+ }
+
+ $factory = new DnsFactory();
+ $resolver = $factory->create($config, $loop);
+ }
+
+ $this->loop = $loop;
+ $this->resolver = $resolver;
+ }
+
+ public function createClient($address)
+ {
+ $loop = $this->loop;
+
+ return $this->resolveAddress($address)->then(function ($address) use ($loop) {
+ $socket = @\stream_socket_client($address, $errno, $errstr);
+ if (!$socket) {
+ throw new Exception('Unable to create client socket: ' . $errstr, $errno);
+ }
+
+ return new Socket($loop, $socket);
+ });
+ }
+
+ public function createServer($address)
+ {
+ $loop = $this->loop;
+
+ return $this->resolveAddress($address)->then(function ($address) use ($loop) {
+ $socket = @\stream_socket_server($address, $errno, $errstr, \STREAM_SERVER_BIND);
+ if (!$socket) {
+ throw new Exception('Unable to create server socket: ' . $errstr, $errno);
+ }
+
+ return new Socket($loop, $socket);
+ });
+ }
+
+ protected function resolveAddress($address)
+ {
+ if (\strpos($address, '://') === false) {
+ $address = 'udp://' . $address;
+ }
+
+ // parse_url() does not accept null ports (random port assignment) => manually remove
+ $nullport = false;
+ if (\substr($address, -2) === ':0') {
+ $address = \substr($address, 0, -2);
+ $nullport = true;
+ }
+
+ $parts = \parse_url($address);
+
+ if (!$parts || !isset($parts['host'])) {
+ return Promise\resolve($address);
+ }
+
+ if ($nullport) {
+ $parts['port'] = 0;
+ }
+
+ // remove square brackets for IPv6 addresses
+ $host = \trim($parts['host'], '[]');
+
+ return $this->resolveHost($host)->then(function ($host) use ($parts) {
+ $address = $parts['scheme'] . '://';
+
+ if (isset($parts['port']) && \strpos($host, ':') !== false) {
+ // enclose IPv6 address in square brackets if a port will be appended
+ $host = '[' . $host . ']';
+ }
+
+ $address .= $host;
+
+ if (isset($parts['port'])) {
+ $address .= ':' . $parts['port'];
+ }
+
+ return $address;
+ });
+ }
+
+ protected function resolveHost($host)
+ {
+ // there's no need to resolve if the host is already given as an IP address
+ if (false !== \filter_var($host, \FILTER_VALIDATE_IP)) {
+ return Promise\resolve($host);
+ }
+
+ $promise = $this->resolver->resolve($host);
+
+ // wrap DNS lookup in order to control cancellation behavior
+ return new Promise\Promise(
+ function ($resolve, $reject) use ($promise) {
+ // forward promise resolution
+ $promise->then($resolve, $reject);
+ },
+ function ($_, $reject) use ($promise) {
+ // reject with custom message once cancelled
+ $reject(new \RuntimeException('Cancelled creating socket during DNS lookup'));
+
+ // (try to) cancel pending DNS lookup, otherwise ignoring its results
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+ }
+ );
+ }
+}
diff --git a/vendor/react/datagram/src/Socket.php b/vendor/react/datagram/src/Socket.php
new file mode 100644
index 0000000..e06723c
--- /dev/null
+++ b/vendor/react/datagram/src/Socket.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace React\Datagram;
+
+use React\EventLoop\LoopInterface;
+use Evenement\EventEmitter;
+use Exception;
+
+class Socket extends EventEmitter implements SocketInterface
+{
+ protected $loop;
+ protected $socket;
+
+ protected $buffer;
+
+ public $bufferSize = 65536;
+
+ public function __construct(LoopInterface $loop, $socket, Buffer $buffer = null)
+ {
+ $this->loop = $loop;
+ $this->socket = $socket;
+
+ if ($buffer === null) {
+ $buffer = new Buffer($loop, $socket);
+ }
+ $this->buffer = $buffer;
+
+ $that = $this;
+ $this->buffer->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error, $that));
+ });
+ $this->buffer->on('close', array($this, 'close'));
+
+ $this->resume();
+ }
+
+ public function getLocalAddress()
+ {
+ if ($this->socket === false) {
+ return null;
+ }
+
+ return $this->sanitizeAddress(@\stream_socket_get_name($this->socket, false));
+ }
+
+ public function getRemoteAddress()
+ {
+ if ($this->socket === false) {
+ return null;
+ }
+
+ return $this->sanitizeAddress(@\stream_socket_get_name($this->socket, true));
+ }
+
+ public function send($data, $remoteAddress = null)
+ {
+ $this->buffer->send($data, $remoteAddress);
+ }
+
+ public function pause()
+ {
+ $this->loop->removeReadStream($this->socket);
+ }
+
+ public function resume()
+ {
+ if ($this->socket !== false) {
+ $this->loop->addReadStream($this->socket, array($this, 'onReceive'));
+ }
+ }
+
+ public function onReceive()
+ {
+ try {
+ $data = $this->handleReceive($peer);
+ }
+ catch (Exception $e) {
+ // emit error message and local socket
+ $this->emit('error', array($e, $this));
+ return;
+ }
+
+ $this->emit('message', array($data, $peer, $this));
+ }
+
+ public function close()
+ {
+ if ($this->socket === false) {
+ return;
+ }
+
+ $this->emit('close', array($this));
+ $this->pause();
+
+ $this->handleClose();
+ $this->socket = false;
+ $this->buffer->close();
+
+ $this->removeAllListeners();
+ }
+
+ public function end()
+ {
+ $this->buffer->end();
+ }
+
+ private function sanitizeAddress($address)
+ {
+ if ($address === false) {
+ return null;
+ }
+
+ // check if this is an IPv6 address which includes multiple colons but no square brackets (PHP < 7.3)
+ $pos = \strrpos($address, ':');
+ if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
+ $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1); // @codeCoverageIgnore
+ }
+ return $address;
+ }
+
+ protected function handleReceive(&$peerAddress)
+ {
+ $data = \stream_socket_recvfrom($this->socket, $this->bufferSize, 0, $peerAddress);
+
+ if ($data === false) {
+ // receiving data failed => remote side rejected one of our packets
+ // due to the nature of UDP, there's no way to tell which one exactly
+ // $peer is not filled either
+
+ throw new Exception('Invalid message');
+ }
+
+ $peerAddress = $this->sanitizeAddress($peerAddress);
+
+ return $data;
+ }
+
+ protected function handleClose()
+ {
+ \fclose($this->socket);
+ }
+}
diff --git a/vendor/react/datagram/src/SocketInterface.php b/vendor/react/datagram/src/SocketInterface.php
new file mode 100644
index 0000000..3292c64
--- /dev/null
+++ b/vendor/react/datagram/src/SocketInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace React\Datagram;
+
+use Evenement\EventEmitterInterface;
+
+/**
+ * interface very similar to React\Stream\Stream
+ *
+ * @event message($data, $remoteAddress, $thisSocket)
+ * @event error($exception, $thisSocket)
+ * @event close($thisSocket)
+ */
+interface SocketInterface extends EventEmitterInterface
+{
+ public function send($data, $remoteAddress = null);
+
+ public function close();
+
+ public function end();
+
+ public function resume();
+
+ public function pause();
+
+ public function getLocalAddress();
+
+ public function getRemoteAddress();
+}
diff --git a/vendor/react/dns/LICENSE b/vendor/react/dns/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/dns/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/dns/composer.json b/vendor/react/dns/composer.json
new file mode 100644
index 0000000..0126343
--- /dev/null
+++ b/vendor/react/dns/composer.json
@@ -0,0 +1,45 @@
+{
+ "name": "react/dns",
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": ["dns", "dns-resolver", "ReactPHP", "async"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.8"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^4.8.35"
+ },
+ "autoload": {
+ "psr-4": { "React\\Dns\\": "src" }
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\Dns\\": "tests" }
+ }
+}
diff --git a/vendor/react/dns/src/BadServerException.php b/vendor/react/dns/src/BadServerException.php
new file mode 100644
index 0000000..3d95213
--- /dev/null
+++ b/vendor/react/dns/src/BadServerException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Dns;
+
+final class BadServerException extends \Exception
+{
+}
diff --git a/vendor/react/dns/src/Config/Config.php b/vendor/react/dns/src/Config/Config.php
new file mode 100644
index 0000000..9677ee5
--- /dev/null
+++ b/vendor/react/dns/src/Config/Config.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace React\Dns\Config;
+
+use RuntimeException;
+
+final class Config
+{
+ /**
+ * Loads the system DNS configuration
+ *
+ * Note that this method may block while loading its internal files and/or
+ * commands and should thus be used with care! While this should be
+ * relatively fast for most systems, it remains unknown if this may block
+ * under certain circumstances. In particular, this method should only be
+ * executed before the loop starts, not while it is running.
+ *
+ * Note that this method will try to access its files and/or commands and
+ * try to parse its output. Currently, this will only parse valid nameserver
+ * entries from its output and will ignore all other output without
+ * complaining.
+ *
+ * Note that the previous section implies that this may return an empty
+ * `Config` object if no valid nameserver entries can be found.
+ *
+ * @return self
+ * @codeCoverageIgnore
+ */
+ public static function loadSystemConfigBlocking()
+ {
+ // Use WMIC output on Windows
+ if (DIRECTORY_SEPARATOR === '\\') {
+ return self::loadWmicBlocking();
+ }
+
+ // otherwise (try to) load from resolv.conf
+ try {
+ return self::loadResolvConfBlocking();
+ } catch (RuntimeException $ignored) {
+ // return empty config if parsing fails (file not found)
+ return new self();
+ }
+ }
+
+ /**
+ * Loads a resolv.conf file (from the given path or default location)
+ *
+ * Note that this method blocks while loading the given path and should
+ * thus be used with care! While this should be relatively fast for normal
+ * resolv.conf files, this may be an issue if this file is located on a slow
+ * device or contains an excessive number of entries. In particular, this
+ * method should only be executed before the loop starts, not while it is
+ * running.
+ *
+ * Note that this method will throw if the given file can not be loaded,
+ * such as if it is not readable or does not exist. In particular, this file
+ * is not available on Windows.
+ *
+ * Currently, this will only parse valid "nameserver X" lines from the
+ * given file contents. Lines can be commented out with "#" and ";" and
+ * invalid lines will be ignored without complaining. See also
+ * `man resolv.conf` for more details.
+ *
+ * Note that the previous section implies that this may return an empty
+ * `Config` object if no valid "nameserver X" lines can be found. See also
+ * `man resolv.conf` which suggests that the DNS server on the localhost
+ * should be used in this case. This is left up to higher level consumers
+ * of this API.
+ *
+ * @param ?string $path (optional) path to resolv.conf file or null=load default location
+ * @return self
+ * @throws RuntimeException if the path can not be loaded (does not exist)
+ */
+ public static function loadResolvConfBlocking($path = null)
+ {
+ if ($path === null) {
+ $path = '/etc/resolv.conf';
+ }
+
+ $contents = @file_get_contents($path);
+ if ($contents === false) {
+ throw new RuntimeException('Unable to load resolv.conf file "' . $path . '"');
+ }
+
+ $matches = array();
+ preg_match_all('/^nameserver\s+(\S+)\s*$/m', $contents, $matches);
+
+ $config = new self();
+ foreach ($matches[1] as $ip) {
+ // remove IPv6 zone ID (`fe80::1%lo0` => `fe80:1`)
+ if (strpos($ip, ':') !== false && ($pos = strpos($ip, '%')) !== false) {
+ $ip = substr($ip, 0, $pos);
+ }
+
+ if (@inet_pton($ip) !== false) {
+ $config->nameservers[] = $ip;
+ }
+ }
+
+ return $config;
+ }
+
+ /**
+ * Loads the DNS configurations from Windows's WMIC (from the given command or default command)
+ *
+ * Note that this method blocks while loading the given command and should
+ * thus be used with care! While this should be relatively fast for normal
+ * WMIC commands, it remains unknown if this may block under certain
+ * circumstances. In particular, this method should only be executed before
+ * the loop starts, not while it is running.
+ *
+ * Note that this method will only try to execute the given command try to
+ * parse its output, irrespective of whether this command exists. In
+ * particular, this command is only available on Windows. Currently, this
+ * will only parse valid nameserver entries from the command output and will
+ * ignore all other output without complaining.
+ *
+ * Note that the previous section implies that this may return an empty
+ * `Config` object if no valid nameserver entries can be found.
+ *
+ * @param ?string $command (advanced) should not be given (NULL) unless you know what you're doing
+ * @return self
+ * @link https://ss64.com/nt/wmic.html
+ */
+ public static function loadWmicBlocking($command = null)
+ {
+ $contents = shell_exec($command === null ? 'wmic NICCONFIG get "DNSServerSearchOrder" /format:CSV' : $command);
+ preg_match_all('/(?<=[{;,"])([\da-f.:]{4,})(?=[};,"])/i', $contents, $matches);
+
+ $config = new self();
+ $config->nameservers = $matches[1];
+
+ return $config;
+ }
+
+ public $nameservers = array();
+}
diff --git a/vendor/react/dns/src/Config/HostsFile.php b/vendor/react/dns/src/Config/HostsFile.php
new file mode 100644
index 0000000..1060231
--- /dev/null
+++ b/vendor/react/dns/src/Config/HostsFile.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace React\Dns\Config;
+
+use RuntimeException;
+
+/**
+ * Represents a static hosts file which maps hostnames to IPs
+ *
+ * Hosts files are used on most systems to avoid actually hitting the DNS for
+ * certain common hostnames.
+ *
+ * Most notably, this file usually contains an entry to map "localhost" to the
+ * local IP. Windows is a notable exception here, as Windows does not actually
+ * include "localhost" in this file by default. To compensate for this, this
+ * class may explicitly be wrapped in another HostsFile instance which
+ * hard-codes these entries for Windows (see also Factory).
+ *
+ * This class mostly exists to abstract the parsing/extraction process so this
+ * can be replaced with a faster alternative in the future.
+ */
+class HostsFile
+{
+ /**
+ * Returns the default path for the hosts file on this system
+ *
+ * @return string
+ * @codeCoverageIgnore
+ */
+ public static function getDefaultPath()
+ {
+ // use static path for all Unix-based systems
+ if (DIRECTORY_SEPARATOR !== '\\') {
+ return '/etc/hosts';
+ }
+
+ // Windows actually stores the path in the registry under
+ // \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DataBasePath
+ $path = '%SystemRoot%\\system32\drivers\etc\hosts';
+
+ $base = getenv('SystemRoot');
+ if ($base === false) {
+ $base = 'C:\\Windows';
+ }
+
+ return str_replace('%SystemRoot%', $base, $path);
+ }
+
+ /**
+ * Loads a hosts file (from the given path or default location)
+ *
+ * Note that this method blocks while loading the given path and should
+ * thus be used with care! While this should be relatively fast for normal
+ * hosts file, this may be an issue if this file is located on a slow device
+ * or contains an excessive number of entries. In particular, this method
+ * should only be executed before the loop starts, not while it is running.
+ *
+ * @param ?string $path (optional) path to hosts file or null=load default location
+ * @return self
+ * @throws RuntimeException if the path can not be loaded (does not exist)
+ */
+ public static function loadFromPathBlocking($path = null)
+ {
+ if ($path === null) {
+ $path = self::getDefaultPath();
+ }
+
+ $contents = @file_get_contents($path);
+ if ($contents === false) {
+ throw new RuntimeException('Unable to load hosts file "' . $path . '"');
+ }
+
+ return new self($contents);
+ }
+
+ private $contents;
+
+ /**
+ * Instantiate new hosts file with the given hosts file contents
+ *
+ * @param string $contents
+ */
+ public function __construct($contents)
+ {
+ // remove all comments from the contents
+ $contents = preg_replace('/[ \t]*#.*/', '', strtolower($contents));
+
+ $this->contents = $contents;
+ }
+
+ /**
+ * Returns all IPs for the given hostname
+ *
+ * @param string $name
+ * @return string[]
+ */
+ public function getIpsForHost($name)
+ {
+ $name = strtolower($name);
+
+ $ips = array();
+ foreach (preg_split('/\r?\n/', $this->contents) as $line) {
+ $parts = preg_split('/\s+/', $line);
+ $ip = array_shift($parts);
+ if ($parts && array_search($name, $parts) !== false) {
+ // remove IPv6 zone ID (`fe80::1%lo0` => `fe80:1`)
+ if (strpos($ip, ':') !== false && ($pos = strpos($ip, '%')) !== false) {
+ $ip = substr($ip, 0, $pos);
+ }
+
+ if (@inet_pton($ip) !== false) {
+ $ips[] = $ip;
+ }
+ }
+ }
+
+ return $ips;
+ }
+
+ /**
+ * Returns all hostnames for the given IPv4 or IPv6 address
+ *
+ * @param string $ip
+ * @return string[]
+ */
+ public function getHostsForIp($ip)
+ {
+ // check binary representation of IP to avoid string case and short notation
+ $ip = @inet_pton($ip);
+ if ($ip === false) {
+ return array();
+ }
+
+ $names = array();
+ foreach (preg_split('/\r?\n/', $this->contents) as $line) {
+ $parts = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
+ $addr = (string) array_shift($parts);
+
+ // remove IPv6 zone ID (`fe80::1%lo0` => `fe80:1`)
+ if (strpos($addr, ':') !== false && ($pos = strpos($addr, '%')) !== false) {
+ $addr = substr($addr, 0, $pos);
+ }
+
+ if (@inet_pton($addr) === $ip) {
+ foreach ($parts as $part) {
+ $names[] = $part;
+ }
+ }
+ }
+
+ return $names;
+ }
+}
diff --git a/vendor/react/dns/src/Model/Message.php b/vendor/react/dns/src/Model/Message.php
new file mode 100644
index 0000000..bac2b10
--- /dev/null
+++ b/vendor/react/dns/src/Model/Message.php
@@ -0,0 +1,230 @@
+<?php
+
+namespace React\Dns\Model;
+
+use React\Dns\Query\Query;
+
+/**
+ * This class represents an outgoing query message or an incoming response message
+ *
+ * @link https://tools.ietf.org/html/rfc1035#section-4.1.1
+ */
+final class Message
+{
+ const TYPE_A = 1;
+ const TYPE_NS = 2;
+ const TYPE_CNAME = 5;
+ const TYPE_SOA = 6;
+ const TYPE_PTR = 12;
+ const TYPE_MX = 15;
+ const TYPE_TXT = 16;
+ const TYPE_AAAA = 28;
+ const TYPE_SRV = 33;
+ const TYPE_SSHFP = 44;
+
+ /**
+ * pseudo-type for EDNS0
+ *
+ * These are included in the additional section and usually not in answer section.
+ * Defined in [RFC 6891](https://tools.ietf.org/html/rfc6891) (or older
+ * [RFC 2671](https://tools.ietf.org/html/rfc2671)).
+ *
+ * The OPT record uses the "class" field to store the maximum size.
+ *
+ * The OPT record uses the "ttl" field to store additional flags.
+ */
+ const TYPE_OPT = 41;
+
+ /**
+ * Sender Policy Framework (SPF) had a dedicated SPF type which has been
+ * deprecated in favor of reusing the existing TXT type.
+ *
+ * @deprecated https://datatracker.ietf.org/doc/html/rfc7208#section-3.1
+ * @see self::TYPE_TXT
+ */
+ const TYPE_SPF = 99;
+
+ const TYPE_ANY = 255;
+ const TYPE_CAA = 257;
+
+ const CLASS_IN = 1;
+
+ const OPCODE_QUERY = 0;
+ const OPCODE_IQUERY = 1; // inverse query
+ const OPCODE_STATUS = 2;
+
+ const RCODE_OK = 0;
+ const RCODE_FORMAT_ERROR = 1;
+ const RCODE_SERVER_FAILURE = 2;
+ const RCODE_NAME_ERROR = 3;
+ const RCODE_NOT_IMPLEMENTED = 4;
+ const RCODE_REFUSED = 5;
+
+ /**
+ * The edns-tcp-keepalive EDNS0 Option
+ *
+ * Option value contains a `?float` with timeout in seconds (in 0.1s steps)
+ * for DNS response or `null` for DNS query.
+ *
+ * @link https://tools.ietf.org/html/rfc7828
+ */
+ const OPT_TCP_KEEPALIVE = 11;
+
+ /**
+ * The EDNS(0) Padding Option
+ *
+ * Option value contains a `string` with binary data (usually variable
+ * number of null bytes)
+ *
+ * @link https://tools.ietf.org/html/rfc7830
+ */
+ const OPT_PADDING = 12;
+
+ /**
+ * Creates a new request message for the given query
+ *
+ * @param Query $query
+ * @return self
+ */
+ public static function createRequestForQuery(Query $query)
+ {
+ $request = new Message();
+ $request->id = self::generateId();
+ $request->rd = true;
+ $request->questions[] = $query;
+
+ return $request;
+ }
+
+ /**
+ * Creates a new response message for the given query with the given answer records
+ *
+ * @param Query $query
+ * @param Record[] $answers
+ * @return self
+ */
+ public static function createResponseWithAnswersForQuery(Query $query, array $answers)
+ {
+ $response = new Message();
+ $response->id = self::generateId();
+ $response->qr = true;
+ $response->rd = true;
+
+ $response->questions[] = $query;
+
+ foreach ($answers as $record) {
+ $response->answers[] = $record;
+ }
+
+ return $response;
+ }
+
+ /**
+ * generates a random 16 bit message ID
+ *
+ * This uses a CSPRNG so that an outside attacker that is sending spoofed
+ * DNS response messages can not guess the message ID to avoid possible
+ * cache poisoning attacks.
+ *
+ * The `random_int()` function is only available on PHP 7+ or when
+ * https://github.com/paragonie/random_compat is installed. As such, using
+ * the latest supported PHP version is highly recommended. This currently
+ * falls back to a less secure random number generator on older PHP versions
+ * in the hope that this system is properly protected against outside
+ * attackers, for example by using one of the common local DNS proxy stubs.
+ *
+ * @return int
+ * @see self::getId()
+ * @codeCoverageIgnore
+ */
+ private static function generateId()
+ {
+ if (function_exists('random_int')) {
+ return random_int(0, 0xffff);
+ }
+ return mt_rand(0, 0xffff);
+ }
+
+ /**
+ * The 16 bit message ID
+ *
+ * The response message ID has to match the request message ID. This allows
+ * the receiver to verify this is the correct response message. An outside
+ * attacker may try to inject fake responses by "guessing" the message ID,
+ * so this should use a proper CSPRNG to avoid possible cache poisoning.
+ *
+ * @var int 16 bit message ID
+ * @see self::generateId()
+ */
+ public $id = 0;
+
+ /**
+ * @var bool Query/Response flag, query=false or response=true
+ */
+ public $qr = false;
+
+ /**
+ * @var int specifies the kind of query (4 bit), see self::OPCODE_* constants
+ * @see self::OPCODE_QUERY
+ */
+ public $opcode = self::OPCODE_QUERY;
+
+ /**
+ *
+ * @var bool Authoritative Answer
+ */
+ public $aa = false;
+
+ /**
+ * @var bool TrunCation
+ */
+ public $tc = false;
+
+ /**
+ * @var bool Recursion Desired
+ */
+ public $rd = false;
+
+ /**
+ * @var bool Recursion Available
+ */
+ public $ra = false;
+
+ /**
+ * @var int response code (4 bit), see self::RCODE_* constants
+ * @see self::RCODE_OK
+ */
+ public $rcode = Message::RCODE_OK;
+
+ /**
+ * An array of Query objects
+ *
+ * ```php
+ * $questions = array(
+ * new Query(
+ * 'reactphp.org',
+ * Message::TYPE_A,
+ * Message::CLASS_IN
+ * )
+ * );
+ * ```
+ *
+ * @var Query[]
+ */
+ public $questions = array();
+
+ /**
+ * @var Record[]
+ */
+ public $answers = array();
+
+ /**
+ * @var Record[]
+ */
+ public $authority = array();
+
+ /**
+ * @var Record[]
+ */
+ public $additional = array();
+}
diff --git a/vendor/react/dns/src/Model/Record.php b/vendor/react/dns/src/Model/Record.php
new file mode 100644
index 0000000..c20403f
--- /dev/null
+++ b/vendor/react/dns/src/Model/Record.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace React\Dns\Model;
+
+/**
+ * This class represents a single resulting record in a response message
+ *
+ * It uses a structure similar to `\React\Dns\Query\Query`, but does include
+ * fields for resulting TTL and resulting record data (IPs etc.).
+ *
+ * @link https://tools.ietf.org/html/rfc1035#section-4.1.3
+ * @see \React\Dns\Query\Query
+ */
+final class Record
+{
+ /**
+ * @var string hostname without trailing dot, for example "reactphp.org"
+ */
+ public $name;
+
+ /**
+ * @var int see Message::TYPE_* constants (UINT16)
+ */
+ public $type;
+
+ /**
+ * Defines the network class, usually `Message::CLASS_IN`.
+ *
+ * For `OPT` records (EDNS0), this defines the maximum message size instead.
+ *
+ * @var int see Message::CLASS_IN constant (UINT16)
+ * @see Message::CLASS_IN
+ */
+ public $class;
+
+ /**
+ * Defines the maximum time-to-live (TTL) in seconds
+ *
+ * For `OPT` records (EDNS0), this defines additional flags instead.
+ *
+ * @var int maximum TTL in seconds (UINT32, most significant bit always unset)
+ * @link https://tools.ietf.org/html/rfc2181#section-8
+ * @link https://tools.ietf.org/html/rfc6891#section-6.1.3 for `OPT` records (EDNS0)
+ */
+ public $ttl;
+
+ /**
+ * The payload data for this record
+ *
+ * The payload data format depends on the record type. As a rule of thumb,
+ * this library will try to express this in a way that can be consumed
+ * easily without having to worry about DNS internals and its binary transport:
+ *
+ * - A:
+ * IPv4 address string, for example "192.168.1.1".
+ *
+ * - AAAA:
+ * IPv6 address string, for example "::1".
+ *
+ * - CNAME / PTR / NS:
+ * The hostname without trailing dot, for example "reactphp.org".
+ *
+ * - TXT:
+ * List of string values, for example `["v=spf1 include:example.com"]`.
+ * This is commonly a list with only a single string value, but this
+ * technically allows multiple strings (0-255 bytes each) in a single
+ * record. This is rarely used and depending on application you may want
+ * to join these together or handle them separately. Each string can
+ * transport any binary data, its character encoding is not defined (often
+ * ASCII/UTF-8 in practice). [RFC 1464](https://tools.ietf.org/html/rfc1464)
+ * suggests using key-value pairs such as `["name=test","version=1"]`, but
+ * interpretation of this is not enforced and left up to consumers of this
+ * library (used for DNS-SD/Zeroconf and others).
+ *
+ * - MX:
+ * Mail server priority (UINT16) and target hostname without trailing dot,
+ * for example `{"priority":10,"target":"mx.example.com"}`.
+ * The payload data uses an associative array with fixed keys "priority"
+ * (also commonly referred to as weight or preference) and "target" (also
+ * referred to as exchange). If a response message contains multiple
+ * records of this type, targets should be sorted by priority (lowest
+ * first) - this is left up to consumers of this library (used for SMTP).
+ *
+ * - SRV:
+ * Service priority (UINT16), service weight (UINT16), service port (UINT16)
+ * and target hostname without trailing dot, for example
+ * `{"priority":10,"weight":50,"port":8080,"target":"example.com"}`.
+ * The payload data uses an associative array with fixed keys "priority",
+ * "weight", "port" and "target" (also referred to as name).
+ * The target may be an empty host name string if the service is decidedly
+ * not available. If a response message contains multiple records of this
+ * type, targets should be sorted by priority (lowest first) and selected
+ * randomly according to their weight - this is left up to consumers of
+ * this library, see also [RFC 2782](https://tools.ietf.org/html/rfc2782)
+ * for more details.
+ *
+ * - SSHFP:
+ * Includes algorithm (UNIT8), fingerprint type (UNIT8) and fingerprint
+ * value as lower case hex string, for example:
+ * `{"algorithm":1,"type":1,"fingerprint":"0123456789abcdef..."}`
+ * See also https://www.iana.org/assignments/dns-sshfp-rr-parameters/dns-sshfp-rr-parameters.xhtml
+ * for algorithm and fingerprint type assignments.
+ *
+ * - SOA:
+ * Includes master hostname without trailing dot, responsible person email
+ * as hostname without trailing dot and serial, refresh, retry, expire and
+ * minimum times in seconds (UINT32 each), for example:
+ * `{"mname":"ns.example.com","rname":"hostmaster.example.com","serial":
+ * 2018082601,"refresh":3600,"retry":1800,"expire":60000,"minimum":3600}`.
+ *
+ * - CAA:
+ * Includes flag (UNIT8), tag string and value string, for example:
+ * `{"flag":128,"tag":"issue","value":"letsencrypt.org"}`
+ *
+ * - OPT:
+ * Special pseudo-type for EDNS0. Includes an array of additional opt codes
+ * with a value according to the respective OPT code. See `Message::OPT_*`
+ * for list of supported OPT codes. Any other OPT code not currently
+ * supported will be an opaque binary string containing the raw data
+ * as transported in the DNS record. For forwards compatibility, you should
+ * not rely on this format for unknown types. Future versions may add
+ * support for new types and this may then parse the payload data
+ * appropriately - this will not be considered a BC break. See also
+ * [RFC 6891](https://tools.ietf.org/html/rfc6891) for more details.
+ *
+ * - Any other unknown type:
+ * An opaque binary string containing the RDATA as transported in the DNS
+ * record. For forwards compatibility, you should not rely on this format
+ * for unknown types. Future versions may add support for new types and
+ * this may then parse the payload data appropriately - this will not be
+ * considered a BC break. See the format definition of known types above
+ * for more details.
+ *
+ * @var string|string[]|array
+ */
+ public $data;
+
+ /**
+ * @param string $name
+ * @param int $type
+ * @param int $class
+ * @param int $ttl
+ * @param string|string[]|array $data
+ */
+ public function __construct($name, $type, $class, $ttl, $data)
+ {
+ $this->name = $name;
+ $this->type = $type;
+ $this->class = $class;
+ $this->ttl = $ttl;
+ $this->data = $data;
+ }
+}
diff --git a/vendor/react/dns/src/Protocol/BinaryDumper.php b/vendor/react/dns/src/Protocol/BinaryDumper.php
new file mode 100644
index 0000000..6f4030f
--- /dev/null
+++ b/vendor/react/dns/src/Protocol/BinaryDumper.php
@@ -0,0 +1,199 @@
+<?php
+
+namespace React\Dns\Protocol;
+
+use React\Dns\Model\Message;
+use React\Dns\Model\Record;
+use React\Dns\Query\Query;
+
+final class BinaryDumper
+{
+ /**
+ * @param Message $message
+ * @return string
+ */
+ public function toBinary(Message $message)
+ {
+ $data = '';
+
+ $data .= $this->headerToBinary($message);
+ $data .= $this->questionToBinary($message->questions);
+ $data .= $this->recordsToBinary($message->answers);
+ $data .= $this->recordsToBinary($message->authority);
+ $data .= $this->recordsToBinary($message->additional);
+
+ return $data;
+ }
+
+ /**
+ * @param Message $message
+ * @return string
+ */
+ private function headerToBinary(Message $message)
+ {
+ $data = '';
+
+ $data .= pack('n', $message->id);
+
+ $flags = 0x00;
+ $flags = ($flags << 1) | ($message->qr ? 1 : 0);
+ $flags = ($flags << 4) | $message->opcode;
+ $flags = ($flags << 1) | ($message->aa ? 1 : 0);
+ $flags = ($flags << 1) | ($message->tc ? 1 : 0);
+ $flags = ($flags << 1) | ($message->rd ? 1 : 0);
+ $flags = ($flags << 1) | ($message->ra ? 1 : 0);
+ $flags = ($flags << 3) | 0; // skip unused zero bit
+ $flags = ($flags << 4) | $message->rcode;
+
+ $data .= pack('n', $flags);
+
+ $data .= pack('n', count($message->questions));
+ $data .= pack('n', count($message->answers));
+ $data .= pack('n', count($message->authority));
+ $data .= pack('n', count($message->additional));
+
+ return $data;
+ }
+
+ /**
+ * @param Query[] $questions
+ * @return string
+ */
+ private function questionToBinary(array $questions)
+ {
+ $data = '';
+
+ foreach ($questions as $question) {
+ $data .= $this->domainNameToBinary($question->name);
+ $data .= pack('n*', $question->type, $question->class);
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param Record[] $records
+ * @return string
+ */
+ private function recordsToBinary(array $records)
+ {
+ $data = '';
+
+ foreach ($records as $record) {
+ /* @var $record Record */
+ switch ($record->type) {
+ case Message::TYPE_A:
+ case Message::TYPE_AAAA:
+ $binary = \inet_pton($record->data);
+ break;
+ case Message::TYPE_CNAME:
+ case Message::TYPE_NS:
+ case Message::TYPE_PTR:
+ $binary = $this->domainNameToBinary($record->data);
+ break;
+ case Message::TYPE_TXT:
+ case Message::TYPE_SPF:
+ $binary = $this->textsToBinary($record->data);
+ break;
+ case Message::TYPE_MX:
+ $binary = \pack(
+ 'n',
+ $record->data['priority']
+ );
+ $binary .= $this->domainNameToBinary($record->data['target']);
+ break;
+ case Message::TYPE_SRV:
+ $binary = \pack(
+ 'n*',
+ $record->data['priority'],
+ $record->data['weight'],
+ $record->data['port']
+ );
+ $binary .= $this->domainNameToBinary($record->data['target']);
+ break;
+ case Message::TYPE_SOA:
+ $binary = $this->domainNameToBinary($record->data['mname']);
+ $binary .= $this->domainNameToBinary($record->data['rname']);
+ $binary .= \pack(
+ 'N*',
+ $record->data['serial'],
+ $record->data['refresh'],
+ $record->data['retry'],
+ $record->data['expire'],
+ $record->data['minimum']
+ );
+ break;
+ case Message::TYPE_CAA:
+ $binary = \pack(
+ 'C*',
+ $record->data['flag'],
+ \strlen($record->data['tag'])
+ );
+ $binary .= $record->data['tag'];
+ $binary .= $record->data['value'];
+ break;
+ case Message::TYPE_SSHFP:
+ $binary = \pack(
+ 'CCH*',
+ $record->data['algorithm'],
+ $record->data['type'],
+ $record->data['fingerprint']
+ );
+ break;
+ case Message::TYPE_OPT:
+ $binary = '';
+ foreach ($record->data as $opt => $value) {
+ if ($opt === Message::OPT_TCP_KEEPALIVE && $value !== null) {
+ $value = \pack('n', round($value * 10));
+ }
+ $binary .= \pack('n*', $opt, \strlen((string) $value)) . $value;
+ }
+ break;
+ default:
+ // RDATA is already stored as binary value for unknown record types
+ $binary = $record->data;
+ }
+
+ $data .= $this->domainNameToBinary($record->name);
+ $data .= \pack('nnNn', $record->type, $record->class, $record->ttl, \strlen($binary));
+ $data .= $binary;
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param string[] $texts
+ * @return string
+ */
+ private function textsToBinary(array $texts)
+ {
+ $data = '';
+ foreach ($texts as $text) {
+ $data .= \chr(\strlen($text)) . $text;
+ }
+ return $data;
+ }
+
+ /**
+ * @param string $host
+ * @return string
+ */
+ private function domainNameToBinary($host)
+ {
+ if ($host === '') {
+ return "\0";
+ }
+
+ // break up domain name at each dot that is not preceeded by a backslash (escaped notation)
+ return $this->textsToBinary(
+ \array_map(
+ 'stripcslashes',
+ \preg_split(
+ '/(?<!\\\\)\./',
+ $host . '.'
+ )
+ )
+ );
+ }
+}
diff --git a/vendor/react/dns/src/Protocol/Parser.php b/vendor/react/dns/src/Protocol/Parser.php
new file mode 100644
index 0000000..011a6e7
--- /dev/null
+++ b/vendor/react/dns/src/Protocol/Parser.php
@@ -0,0 +1,356 @@
+<?php
+
+namespace React\Dns\Protocol;
+
+use React\Dns\Model\Message;
+use React\Dns\Model\Record;
+use React\Dns\Query\Query;
+use InvalidArgumentException;
+
+/**
+ * DNS protocol parser
+ *
+ * Obsolete and uncommon types and classes are not implemented.
+ */
+final class Parser
+{
+ /**
+ * Parses the given raw binary message into a Message object
+ *
+ * @param string $data
+ * @throws InvalidArgumentException
+ * @return Message
+ */
+ public function parseMessage($data)
+ {
+ $message = $this->parse($data, 0);
+ if ($message === null) {
+ throw new InvalidArgumentException('Unable to parse binary message');
+ }
+
+ return $message;
+ }
+
+ /**
+ * @param string $data
+ * @param int $consumed
+ * @return ?Message
+ */
+ private function parse($data, $consumed)
+ {
+ if (!isset($data[12 - 1])) {
+ return null;
+ }
+
+ list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_values(unpack('n*', substr($data, 0, 12)));
+
+ $message = new Message();
+ $message->id = $id;
+ $message->rcode = $fields & 0xf;
+ $message->ra = (($fields >> 7) & 1) === 1;
+ $message->rd = (($fields >> 8) & 1) === 1;
+ $message->tc = (($fields >> 9) & 1) === 1;
+ $message->aa = (($fields >> 10) & 1) === 1;
+ $message->opcode = ($fields >> 11) & 0xf;
+ $message->qr = (($fields >> 15) & 1) === 1;
+ $consumed += 12;
+
+ // parse all questions
+ for ($i = $qdCount; $i > 0; --$i) {
+ list($question, $consumed) = $this->parseQuestion($data, $consumed);
+ if ($question === null) {
+ return null;
+ } else {
+ $message->questions[] = $question;
+ }
+ }
+
+ // parse all answer records
+ for ($i = $anCount; $i > 0; --$i) {
+ list($record, $consumed) = $this->parseRecord($data, $consumed);
+ if ($record === null) {
+ return null;
+ } else {
+ $message->answers[] = $record;
+ }
+ }
+
+ // parse all authority records
+ for ($i = $nsCount; $i > 0; --$i) {
+ list($record, $consumed) = $this->parseRecord($data, $consumed);
+ if ($record === null) {
+ return null;
+ } else {
+ $message->authority[] = $record;
+ }
+ }
+
+ // parse all additional records
+ for ($i = $arCount; $i > 0; --$i) {
+ list($record, $consumed) = $this->parseRecord($data, $consumed);
+ if ($record === null) {
+ return null;
+ } else {
+ $message->additional[] = $record;
+ }
+ }
+
+ return $message;
+ }
+
+ /**
+ * @param string $data
+ * @param int $consumed
+ * @return array
+ */
+ private function parseQuestion($data, $consumed)
+ {
+ list($labels, $consumed) = $this->readLabels($data, $consumed);
+
+ if ($labels === null || !isset($data[$consumed + 4 - 1])) {
+ return array(null, null);
+ }
+
+ list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
+ $consumed += 4;
+
+ return array(
+ new Query(
+ implode('.', $labels),
+ $type,
+ $class
+ ),
+ $consumed
+ );
+ }
+
+ /**
+ * @param string $data
+ * @param int $consumed
+ * @return array An array with a parsed Record on success or array with null if data is invalid/incomplete
+ */
+ private function parseRecord($data, $consumed)
+ {
+ list($name, $consumed) = $this->readDomain($data, $consumed);
+
+ if ($name === null || !isset($data[$consumed + 10 - 1])) {
+ return array(null, null);
+ }
+
+ list($type, $class) = array_values(unpack('n*', substr($data, $consumed, 4)));
+ $consumed += 4;
+
+ list($ttl) = array_values(unpack('N', substr($data, $consumed, 4)));
+ $consumed += 4;
+
+ // TTL is a UINT32 that must not have most significant bit set for BC reasons
+ if ($ttl < 0 || $ttl >= 1 << 31) {
+ $ttl = 0;
+ }
+
+ list($rdLength) = array_values(unpack('n', substr($data, $consumed, 2)));
+ $consumed += 2;
+
+ if (!isset($data[$consumed + $rdLength - 1])) {
+ return array(null, null);
+ }
+
+ $rdata = null;
+ $expected = $consumed + $rdLength;
+
+ if (Message::TYPE_A === $type) {
+ if ($rdLength === 4) {
+ $rdata = inet_ntop(substr($data, $consumed, $rdLength));
+ $consumed += $rdLength;
+ }
+ } elseif (Message::TYPE_AAAA === $type) {
+ if ($rdLength === 16) {
+ $rdata = inet_ntop(substr($data, $consumed, $rdLength));
+ $consumed += $rdLength;
+ }
+ } elseif (Message::TYPE_CNAME === $type || Message::TYPE_PTR === $type || Message::TYPE_NS === $type) {
+ list($rdata, $consumed) = $this->readDomain($data, $consumed);
+ } elseif (Message::TYPE_TXT === $type || Message::TYPE_SPF === $type) {
+ $rdata = array();
+ while ($consumed < $expected) {
+ $len = ord($data[$consumed]);
+ $rdata[] = (string)substr($data, $consumed + 1, $len);
+ $consumed += $len + 1;
+ }
+ } elseif (Message::TYPE_MX === $type) {
+ if ($rdLength > 2) {
+ list($priority) = array_values(unpack('n', substr($data, $consumed, 2)));
+ list($target, $consumed) = $this->readDomain($data, $consumed + 2);
+
+ $rdata = array(
+ 'priority' => $priority,
+ 'target' => $target
+ );
+ }
+ } elseif (Message::TYPE_SRV === $type) {
+ if ($rdLength > 6) {
+ list($priority, $weight, $port) = array_values(unpack('n*', substr($data, $consumed, 6)));
+ list($target, $consumed) = $this->readDomain($data, $consumed + 6);
+
+ $rdata = array(
+ 'priority' => $priority,
+ 'weight' => $weight,
+ 'port' => $port,
+ 'target' => $target
+ );
+ }
+ } elseif (Message::TYPE_SSHFP === $type) {
+ if ($rdLength > 2) {
+ list($algorithm, $hash) = \array_values(\unpack('C*', \substr($data, $consumed, 2)));
+ $fingerprint = \bin2hex(\substr($data, $consumed + 2, $rdLength - 2));
+ $consumed += $rdLength;
+
+ $rdata = array(
+ 'algorithm' => $algorithm,
+ 'type' => $hash,
+ 'fingerprint' => $fingerprint
+ );
+ }
+ } elseif (Message::TYPE_SOA === $type) {
+ list($mname, $consumed) = $this->readDomain($data, $consumed);
+ list($rname, $consumed) = $this->readDomain($data, $consumed);
+
+ if ($mname !== null && $rname !== null && isset($data[$consumed + 20 - 1])) {
+ list($serial, $refresh, $retry, $expire, $minimum) = array_values(unpack('N*', substr($data, $consumed, 20)));
+ $consumed += 20;
+
+ $rdata = array(
+ 'mname' => $mname,
+ 'rname' => $rname,
+ 'serial' => $serial,
+ 'refresh' => $refresh,
+ 'retry' => $retry,
+ 'expire' => $expire,
+ 'minimum' => $minimum
+ );
+ }
+ } elseif (Message::TYPE_OPT === $type) {
+ $rdata = array();
+ while (isset($data[$consumed + 4 - 1])) {
+ list($code, $length) = array_values(unpack('n*', substr($data, $consumed, 4)));
+ $value = (string) substr($data, $consumed + 4, $length);
+ if ($code === Message::OPT_TCP_KEEPALIVE && $value === '') {
+ $value = null;
+ } elseif ($code === Message::OPT_TCP_KEEPALIVE && $length === 2) {
+ list($value) = array_values(unpack('n', $value));
+ $value = round($value * 0.1, 1);
+ } elseif ($code === Message::OPT_TCP_KEEPALIVE) {
+ break;
+ }
+ $rdata[$code] = $value;
+ $consumed += 4 + $length;
+ }
+ } elseif (Message::TYPE_CAA === $type) {
+ if ($rdLength > 3) {
+ list($flag, $tagLength) = array_values(unpack('C*', substr($data, $consumed, 2)));
+
+ if ($tagLength > 0 && $rdLength - 2 - $tagLength > 0) {
+ $tag = substr($data, $consumed + 2, $tagLength);
+ $value = substr($data, $consumed + 2 + $tagLength, $rdLength - 2 - $tagLength);
+ $consumed += $rdLength;
+
+ $rdata = array(
+ 'flag' => $flag,
+ 'tag' => $tag,
+ 'value' => $value
+ );
+ }
+ }
+ } else {
+ // unknown types simply parse rdata as an opaque binary string
+ $rdata = substr($data, $consumed, $rdLength);
+ $consumed += $rdLength;
+ }
+
+ // ensure parsing record data consumes expact number of bytes indicated in record length
+ if ($consumed !== $expected || $rdata === null) {
+ return array(null, null);
+ }
+
+ return array(
+ new Record($name, $type, $class, $ttl, $rdata),
+ $consumed
+ );
+ }
+
+ private function readDomain($data, $consumed)
+ {
+ list ($labels, $consumed) = $this->readLabels($data, $consumed);
+
+ if ($labels === null) {
+ return array(null, null);
+ }
+
+ // use escaped notation for each label part, then join using dots
+ return array(
+ \implode(
+ '.',
+ \array_map(
+ function ($label) {
+ return \addcslashes($label, "\0..\40.\177");
+ },
+ $labels
+ )
+ ),
+ $consumed
+ );
+ }
+
+ /**
+ * @param string $data
+ * @param int $consumed
+ * @param int $compressionDepth maximum depth for compressed labels to avoid unreasonable recursion
+ * @return array
+ */
+ private function readLabels($data, $consumed, $compressionDepth = 127)
+ {
+ $labels = array();
+
+ while (true) {
+ if (!isset($data[$consumed])) {
+ return array(null, null);
+ }
+
+ $length = \ord($data[$consumed]);
+
+ // end of labels reached
+ if ($length === 0) {
+ $consumed += 1;
+ break;
+ }
+
+ // first two bits set? this is a compressed label (14 bit pointer offset)
+ if (($length & 0xc0) === 0xc0 && isset($data[$consumed + 1]) && $compressionDepth) {
+ $offset = ($length & ~0xc0) << 8 | \ord($data[$consumed + 1]);
+ if ($offset >= $consumed) {
+ return array(null, null);
+ }
+
+ $consumed += 2;
+ list($newLabels) = $this->readLabels($data, $offset, $compressionDepth - 1);
+
+ if ($newLabels === null) {
+ return array(null, null);
+ }
+
+ $labels = array_merge($labels, $newLabels);
+ break;
+ }
+
+ // length MUST be 0-63 (6 bits only) and data has to be large enough
+ if ($length & 0xc0 || !isset($data[$consumed + $length - 1])) {
+ return array(null, null);
+ }
+
+ $labels[] = substr($data, $consumed + 1, $length);
+ $consumed += $length + 1;
+ }
+
+ return array($labels, $consumed);
+ }
+}
diff --git a/vendor/react/dns/src/Query/CachingExecutor.php b/vendor/react/dns/src/Query/CachingExecutor.php
new file mode 100644
index 0000000..e530b24
--- /dev/null
+++ b/vendor/react/dns/src/Query/CachingExecutor.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Cache\CacheInterface;
+use React\Dns\Model\Message;
+use React\Promise\Promise;
+
+final class CachingExecutor implements ExecutorInterface
+{
+ /**
+ * Default TTL for negative responses (NXDOMAIN etc.).
+ *
+ * @internal
+ */
+ const TTL = 60;
+
+ private $executor;
+ private $cache;
+
+ public function __construct(ExecutorInterface $executor, CacheInterface $cache)
+ {
+ $this->executor = $executor;
+ $this->cache = $cache;
+ }
+
+ public function query(Query $query)
+ {
+ $id = $query->name . ':' . $query->type . ':' . $query->class;
+ $cache = $this->cache;
+ $that = $this;
+ $executor = $this->executor;
+
+ $pending = $cache->get($id);
+ return new Promise(function ($resolve, $reject) use ($query, $id, $cache, $executor, &$pending, $that) {
+ $pending->then(
+ function ($message) use ($query, $id, $cache, $executor, &$pending, $that) {
+ // return cached response message on cache hit
+ if ($message !== null) {
+ return $message;
+ }
+
+ // perform DNS lookup if not already cached
+ return $pending = $executor->query($query)->then(
+ function (Message $message) use ($cache, $id, $that) {
+ // DNS response message received => store in cache when not truncated and return
+ if (!$message->tc) {
+ $cache->set($id, $message, $that->ttl($message));
+ }
+
+ return $message;
+ }
+ );
+ }
+ )->then($resolve, function ($e) use ($reject, &$pending) {
+ $reject($e);
+ $pending = null;
+ });
+ }, function ($_, $reject) use (&$pending, $query) {
+ $reject(new \RuntimeException('DNS query for ' . $query->describe() . ' has been cancelled'));
+ $pending->cancel();
+ $pending = null;
+ });
+ }
+
+ /**
+ * @param Message $message
+ * @return int
+ * @internal
+ */
+ public function ttl(Message $message)
+ {
+ // select TTL from answers (should all be the same), use smallest value if available
+ // @link https://tools.ietf.org/html/rfc2181#section-5.2
+ $ttl = null;
+ foreach ($message->answers as $answer) {
+ if ($ttl === null || $answer->ttl < $ttl) {
+ $ttl = $answer->ttl;
+ }
+ }
+
+ if ($ttl === null) {
+ $ttl = self::TTL;
+ }
+
+ return $ttl;
+ }
+}
diff --git a/vendor/react/dns/src/Query/CancellationException.php b/vendor/react/dns/src/Query/CancellationException.php
new file mode 100644
index 0000000..5432b36
--- /dev/null
+++ b/vendor/react/dns/src/Query/CancellationException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Dns\Query;
+
+final class CancellationException extends \RuntimeException
+{
+}
diff --git a/vendor/react/dns/src/Query/CoopExecutor.php b/vendor/react/dns/src/Query/CoopExecutor.php
new file mode 100644
index 0000000..e3f913b
--- /dev/null
+++ b/vendor/react/dns/src/Query/CoopExecutor.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Promise\Promise;
+
+/**
+ * Cooperatively resolves hosts via the given base executor to ensure same query is not run concurrently
+ *
+ * Wraps an existing `ExecutorInterface` to keep tracking of pending queries
+ * and only starts a new query when the same query is not already pending. Once
+ * the underlying query is fulfilled/rejected, it will forward its value to all
+ * promises awaiting the same query.
+ *
+ * This means it will not limit concurrency for queries that differ, for example
+ * when sending many queries for different host names or types.
+ *
+ * This is useful because all executors are entirely async and as such allow you
+ * to execute any number of queries concurrently. You should probably limit the
+ * number of concurrent queries in your application or you're very likely going
+ * to face rate limitations and bans on the resolver end. For many common
+ * applications, you may want to avoid sending the same query multiple times
+ * when the first one is still pending, so you will likely want to use this in
+ * combination with some other executor like this:
+ *
+ * ```php
+ * $executor = new CoopExecutor(
+ * new RetryExecutor(
+ * new TimeoutExecutor(
+ * new UdpTransportExecutor($nameserver),
+ * 3.0
+ * )
+ * )
+ * );
+ * ```
+ */
+final class CoopExecutor implements ExecutorInterface
+{
+ private $executor;
+ private $pending = array();
+ private $counts = array();
+
+ public function __construct(ExecutorInterface $base)
+ {
+ $this->executor = $base;
+ }
+
+ public function query(Query $query)
+ {
+ $key = $this->serializeQueryToIdentity($query);
+ if (isset($this->pending[$key])) {
+ // same query is already pending, so use shared reference to pending query
+ $promise = $this->pending[$key];
+ ++$this->counts[$key];
+ } else {
+ // no such query pending, so start new query and keep reference until it's fulfilled or rejected
+ $promise = $this->executor->query($query);
+ $this->pending[$key] = $promise;
+ $this->counts[$key] = 1;
+
+ $pending =& $this->pending;
+ $counts =& $this->counts;
+ $promise->then(function () use ($key, &$pending, &$counts) {
+ unset($pending[$key], $counts[$key]);
+ }, function () use ($key, &$pending, &$counts) {
+ unset($pending[$key], $counts[$key]);
+ });
+ }
+
+ // Return a child promise awaiting the pending query.
+ // Cancelling this child promise should only cancel the pending query
+ // when no other child promise is awaiting the same query.
+ $pending =& $this->pending;
+ $counts =& $this->counts;
+ return new Promise(function ($resolve, $reject) use ($promise) {
+ $promise->then($resolve, $reject);
+ }, function () use (&$promise, $key, $query, &$pending, &$counts) {
+ if (--$counts[$key] < 1) {
+ unset($pending[$key], $counts[$key]);
+ $promise->cancel();
+ $promise = null;
+ }
+ throw new \RuntimeException('DNS query for ' . $query->describe() . ' has been cancelled');
+ });
+ }
+
+ private function serializeQueryToIdentity(Query $query)
+ {
+ return sprintf('%s:%s:%s', $query->name, $query->type, $query->class);
+ }
+}
diff --git a/vendor/react/dns/src/Query/ExecutorInterface.php b/vendor/react/dns/src/Query/ExecutorInterface.php
new file mode 100644
index 0000000..b356dc6
--- /dev/null
+++ b/vendor/react/dns/src/Query/ExecutorInterface.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace React\Dns\Query;
+
+interface ExecutorInterface
+{
+ /**
+ * Executes a query and will return a response message
+ *
+ * It returns a Promise which either fulfills with a response
+ * `React\Dns\Model\Message` on success or rejects with an `Exception` if
+ * the query is not successful. A response message may indicate an error
+ * condition in its `rcode`, but this is considered a valid response message.
+ *
+ * ```php
+ * $executor->query($query)->then(
+ * function (React\Dns\Model\Message $response) {
+ * // response message successfully received
+ * var_dump($response->rcode, $response->answers);
+ * },
+ * function (Exception $error) {
+ * // failed to query due to $error
+ * }
+ * );
+ * ```
+ *
+ * The returned Promise MUST be implemented in such a way that it can be
+ * cancelled when it is still pending. Cancelling a pending promise MUST
+ * reject its value with an Exception. It SHOULD clean up any underlying
+ * resources and references as applicable.
+ *
+ * ```php
+ * $promise = $executor->query($query);
+ *
+ * $promise->cancel();
+ * ```
+ *
+ * @param Query $query
+ * @return \React\Promise\PromiseInterface<\React\Dns\Model\Message,\Exception>
+ * resolves with response message on success or rejects with an Exception on error
+ */
+ public function query(Query $query);
+}
diff --git a/vendor/react/dns/src/Query/FallbackExecutor.php b/vendor/react/dns/src/Query/FallbackExecutor.php
new file mode 100644
index 0000000..83bd360
--- /dev/null
+++ b/vendor/react/dns/src/Query/FallbackExecutor.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Promise\Promise;
+
+final class FallbackExecutor implements ExecutorInterface
+{
+ private $executor;
+ private $fallback;
+
+ public function __construct(ExecutorInterface $executor, ExecutorInterface $fallback)
+ {
+ $this->executor = $executor;
+ $this->fallback = $fallback;
+ }
+
+ public function query(Query $query)
+ {
+ $cancelled = false;
+ $fallback = $this->fallback;
+ $promise = $this->executor->query($query);
+
+ return new Promise(function ($resolve, $reject) use (&$promise, $fallback, $query, &$cancelled) {
+ $promise->then($resolve, function (\Exception $e1) use ($fallback, $query, $resolve, $reject, &$cancelled, &$promise) {
+ // reject if primary resolution rejected due to cancellation
+ if ($cancelled) {
+ $reject($e1);
+ return;
+ }
+
+ // start fallback query if primary query rejected
+ $promise = $fallback->query($query)->then($resolve, function (\Exception $e2) use ($e1, $reject) {
+ $append = $e2->getMessage();
+ if (($pos = strpos($append, ':')) !== false) {
+ $append = substr($append, $pos + 2);
+ }
+
+ // reject with combined error message if both queries fail
+ $reject(new \RuntimeException($e1->getMessage() . '. ' . $append));
+ });
+ });
+ }, function () use (&$promise, &$cancelled) {
+ // cancel pending query (primary or fallback)
+ $cancelled = true;
+ $promise->cancel();
+ });
+ }
+}
diff --git a/vendor/react/dns/src/Query/HostsFileExecutor.php b/vendor/react/dns/src/Query/HostsFileExecutor.php
new file mode 100644
index 0000000..d6e2d93
--- /dev/null
+++ b/vendor/react/dns/src/Query/HostsFileExecutor.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Dns\Config\HostsFile;
+use React\Dns\Model\Message;
+use React\Dns\Model\Record;
+use React\Promise;
+
+/**
+ * Resolves hosts from the given HostsFile or falls back to another executor
+ *
+ * If the host is found in the hosts file, it will not be passed to the actual
+ * DNS executor. If the host is not found in the hosts file, it will be passed
+ * to the DNS executor as a fallback.
+ */
+final class HostsFileExecutor implements ExecutorInterface
+{
+ private $hosts;
+ private $fallback;
+
+ public function __construct(HostsFile $hosts, ExecutorInterface $fallback)
+ {
+ $this->hosts = $hosts;
+ $this->fallback = $fallback;
+ }
+
+ public function query(Query $query)
+ {
+ if ($query->class === Message::CLASS_IN && ($query->type === Message::TYPE_A || $query->type === Message::TYPE_AAAA)) {
+ // forward lookup for type A or AAAA
+ $records = array();
+ $expectsColon = $query->type === Message::TYPE_AAAA;
+ foreach ($this->hosts->getIpsForHost($query->name) as $ip) {
+ // ensure this is an IPv4/IPV6 address according to query type
+ if ((strpos($ip, ':') !== false) === $expectsColon) {
+ $records[] = new Record($query->name, $query->type, $query->class, 0, $ip);
+ }
+ }
+
+ if ($records) {
+ return Promise\resolve(
+ Message::createResponseWithAnswersForQuery($query, $records)
+ );
+ }
+ } elseif ($query->class === Message::CLASS_IN && $query->type === Message::TYPE_PTR) {
+ // reverse lookup: extract IPv4 or IPv6 from special `.arpa` domain
+ $ip = $this->getIpFromHost($query->name);
+
+ if ($ip !== null) {
+ $records = array();
+ foreach ($this->hosts->getHostsForIp($ip) as $host) {
+ $records[] = new Record($query->name, $query->type, $query->class, 0, $host);
+ }
+
+ if ($records) {
+ return Promise\resolve(
+ Message::createResponseWithAnswersForQuery($query, $records)
+ );
+ }
+ }
+ }
+
+ return $this->fallback->query($query);
+ }
+
+ private function getIpFromHost($host)
+ {
+ if (substr($host, -13) === '.in-addr.arpa') {
+ // IPv4: read as IP and reverse bytes
+ $ip = @inet_pton(substr($host, 0, -13));
+ if ($ip === false || isset($ip[4])) {
+ return null;
+ }
+
+ return inet_ntop(strrev($ip));
+ } elseif (substr($host, -9) === '.ip6.arpa') {
+ // IPv6: replace dots, reverse nibbles and interpret as hexadecimal string
+ $ip = @inet_ntop(pack('H*', strrev(str_replace('.', '', substr($host, 0, -9)))));
+ if ($ip === false) {
+ return null;
+ }
+
+ return $ip;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/vendor/react/dns/src/Query/Query.php b/vendor/react/dns/src/Query/Query.php
new file mode 100644
index 0000000..a3dcfb5
--- /dev/null
+++ b/vendor/react/dns/src/Query/Query.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Dns\Model\Message;
+
+/**
+ * This class represents a single question in a query/response message
+ *
+ * It uses a structure similar to `\React\Dns\Message\Record`, but does not
+ * contain fields for resulting TTL and resulting record data (IPs etc.).
+ *
+ * @link https://tools.ietf.org/html/rfc1035#section-4.1.2
+ * @see \React\Dns\Message\Record
+ */
+final class Query
+{
+ /**
+ * @var string query name, i.e. hostname to look up
+ */
+ public $name;
+
+ /**
+ * @var int query type (aka QTYPE), see Message::TYPE_* constants
+ */
+ public $type;
+
+ /**
+ * @var int query class (aka QCLASS), see Message::CLASS_IN constant
+ */
+ public $class;
+
+ /**
+ * @param string $name query name, i.e. hostname to look up
+ * @param int $type query type, see Message::TYPE_* constants
+ * @param int $class query class, see Message::CLASS_IN constant
+ */
+ public function __construct($name, $type, $class)
+ {
+ $this->name = $name;
+ $this->type = $type;
+ $this->class = $class;
+ }
+
+ /**
+ * Describes the hostname and query type/class for this query
+ *
+ * The output format is supposed to be human readable and is subject to change.
+ * The format is inspired by RFC 3597 when handling unkown types/classes.
+ *
+ * @return string "example.com (A)" or "example.com (CLASS0 TYPE1234)"
+ * @link https://tools.ietf.org/html/rfc3597
+ */
+ public function describe()
+ {
+ $class = $this->class !== Message::CLASS_IN ? 'CLASS' . $this->class . ' ' : '';
+
+ $type = 'TYPE' . $this->type;
+ $ref = new \ReflectionClass('React\Dns\Model\Message');
+ foreach ($ref->getConstants() as $name => $value) {
+ if ($value === $this->type && \strpos($name, 'TYPE_') === 0) {
+ $type = \substr($name, 5);
+ break;
+ }
+ }
+
+ return $this->name . ' (' . $class . $type . ')';
+ }
+}
diff --git a/vendor/react/dns/src/Query/RetryExecutor.php b/vendor/react/dns/src/Query/RetryExecutor.php
new file mode 100644
index 0000000..7efcacc
--- /dev/null
+++ b/vendor/react/dns/src/Query/RetryExecutor.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+
+final class RetryExecutor implements ExecutorInterface
+{
+ private $executor;
+ private $retries;
+
+ public function __construct(ExecutorInterface $executor, $retries = 2)
+ {
+ $this->executor = $executor;
+ $this->retries = $retries;
+ }
+
+ public function query(Query $query)
+ {
+ return $this->tryQuery($query, $this->retries);
+ }
+
+ public function tryQuery(Query $query, $retries)
+ {
+ $deferred = new Deferred(function () use (&$promise) {
+ if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
+ $promise->cancel();
+ }
+ });
+
+ $success = function ($value) use ($deferred, &$errorback) {
+ $errorback = null;
+ $deferred->resolve($value);
+ };
+
+ $executor = $this->executor;
+ $errorback = function ($e) use ($deferred, &$promise, $query, $success, &$errorback, &$retries, $executor) {
+ if (!$e instanceof TimeoutException) {
+ $errorback = null;
+ $deferred->reject($e);
+ } elseif ($retries <= 0) {
+ $errorback = null;
+ $deferred->reject($e = new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: too many retries',
+ 0,
+ $e
+ ));
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as &$one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as &$arg) {
+ if ($arg instanceof \Closure) {
+ $arg = 'Object(' . \get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ } else {
+ --$retries;
+ $promise = $executor->query($query)->then(
+ $success,
+ $errorback
+ );
+ }
+ };
+
+ $promise = $this->executor->query($query)->then(
+ $success,
+ $errorback
+ );
+
+ return $deferred->promise();
+ }
+}
diff --git a/vendor/react/dns/src/Query/SelectiveTransportExecutor.php b/vendor/react/dns/src/Query/SelectiveTransportExecutor.php
new file mode 100644
index 0000000..0f0ca5d
--- /dev/null
+++ b/vendor/react/dns/src/Query/SelectiveTransportExecutor.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Promise\Promise;
+
+/**
+ * Send DNS queries over a UDP or TCP/IP stream transport.
+ *
+ * This class will automatically choose the correct transport protocol to send
+ * a DNS query to your DNS server. It will always try to send it over the more
+ * efficient UDP transport first. If this query yields a size related issue
+ * (truncated messages), it will retry over a streaming TCP/IP transport.
+ *
+ * For more advanced usages one can utilize this class directly.
+ * The following example looks up the `IPv6` address for `reactphp.org`.
+ *
+ * ```php
+ * $executor = new SelectiveTransportExecutor($udpExecutor, $tcpExecutor);
+ *
+ * $executor->query(
+ * new Query($name, Message::TYPE_AAAA, Message::CLASS_IN)
+ * )->then(function (Message $message) {
+ * foreach ($message->answers as $answer) {
+ * echo 'IPv6: ' . $answer->data . PHP_EOL;
+ * }
+ * }, 'printf');
+ * ```
+ *
+ * Note that this executor only implements the logic to select the correct
+ * transport for the given DNS query. Implementing the correct transport logic,
+ * implementing timeouts and any retry logic is left up to the given executors,
+ * see also [`UdpTransportExecutor`](#udptransportexecutor) and
+ * [`TcpTransportExecutor`](#tcptransportexecutor) for more details.
+ *
+ * Note that this executor is entirely async and as such allows you to execute
+ * any number of queries concurrently. You should probably limit the number of
+ * concurrent queries in your application or you're very likely going to face
+ * rate limitations and bans on the resolver end. For many common applications,
+ * you may want to avoid sending the same query multiple times when the first
+ * one is still pending, so you will likely want to use this in combination with
+ * a `CoopExecutor` like this:
+ *
+ * ```php
+ * $executor = new CoopExecutor(
+ * new SelectiveTransportExecutor(
+ * $datagramExecutor,
+ * $streamExecutor
+ * )
+ * );
+ * ```
+ */
+class SelectiveTransportExecutor implements ExecutorInterface
+{
+ private $datagramExecutor;
+ private $streamExecutor;
+
+ public function __construct(ExecutorInterface $datagramExecutor, ExecutorInterface $streamExecutor)
+ {
+ $this->datagramExecutor = $datagramExecutor;
+ $this->streamExecutor = $streamExecutor;
+ }
+
+ public function query(Query $query)
+ {
+ $stream = $this->streamExecutor;
+ $pending = $this->datagramExecutor->query($query);
+
+ return new Promise(function ($resolve, $reject) use (&$pending, $stream, $query) {
+ $pending->then(
+ $resolve,
+ function ($e) use (&$pending, $stream, $query, $resolve, $reject) {
+ if ($e->getCode() === (\defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90)) {
+ $pending = $stream->query($query)->then($resolve, $reject);
+ } else {
+ $reject($e);
+ }
+ }
+ );
+ }, function () use (&$pending) {
+ $pending->cancel();
+ $pending = null;
+ });
+ }
+}
diff --git a/vendor/react/dns/src/Query/TcpTransportExecutor.php b/vendor/react/dns/src/Query/TcpTransportExecutor.php
new file mode 100644
index 0000000..6644e16
--- /dev/null
+++ b/vendor/react/dns/src/Query/TcpTransportExecutor.php
@@ -0,0 +1,367 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Dns\Model\Message;
+use React\Dns\Protocol\BinaryDumper;
+use React\Dns\Protocol\Parser;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Deferred;
+
+/**
+ * Send DNS queries over a TCP/IP stream transport.
+ *
+ * This is one of the main classes that send a DNS query to your DNS server.
+ *
+ * For more advanced usages one can utilize this class directly.
+ * The following example looks up the `IPv6` address for `reactphp.org`.
+ *
+ * ```php
+ * $executor = new TcpTransportExecutor('8.8.8.8:53');
+ *
+ * $executor->query(
+ * new Query($name, Message::TYPE_AAAA, Message::CLASS_IN)
+ * )->then(function (Message $message) {
+ * foreach ($message->answers as $answer) {
+ * echo 'IPv6: ' . $answer->data . PHP_EOL;
+ * }
+ * }, 'printf');
+ * ```
+ *
+ * See also [example #92](examples).
+ *
+ * Note that this executor does not implement a timeout, so you will very likely
+ * want to use this in combination with a `TimeoutExecutor` like this:
+ *
+ * ```php
+ * $executor = new TimeoutExecutor(
+ * new TcpTransportExecutor($nameserver),
+ * 3.0
+ * );
+ * ```
+ *
+ * Unlike the `UdpTransportExecutor`, this class uses a reliable TCP/IP
+ * transport, so you do not necessarily have to implement any retry logic.
+ *
+ * Note that this executor is entirely async and as such allows you to execute
+ * queries concurrently. The first query will establish a TCP/IP socket
+ * connection to the DNS server which will be kept open for a short period.
+ * Additional queries will automatically reuse this existing socket connection
+ * to the DNS server, will pipeline multiple requests over this single
+ * connection and will keep an idle connection open for a short period. The
+ * initial TCP/IP connection overhead may incur a slight delay if you only send
+ * occasional queries – when sending a larger number of concurrent queries over
+ * an existing connection, it becomes increasingly more efficient and avoids
+ * creating many concurrent sockets like the UDP-based executor. You may still
+ * want to limit the number of (concurrent) queries in your application or you
+ * may be facing rate limitations and bans on the resolver end. For many common
+ * applications, you may want to avoid sending the same query multiple times
+ * when the first one is still pending, so you will likely want to use this in
+ * combination with a `CoopExecutor` like this:
+ *
+ * ```php
+ * $executor = new CoopExecutor(
+ * new TimeoutExecutor(
+ * new TcpTransportExecutor($nameserver),
+ * 3.0
+ * )
+ * );
+ * ```
+ *
+ * > Internally, this class uses PHP's TCP/IP sockets and does not take advantage
+ * of [react/socket](https://github.com/reactphp/socket) purely for
+ * organizational reasons to avoid a cyclic dependency between the two
+ * packages. Higher-level components should take advantage of the Socket
+ * component instead of reimplementing this socket logic from scratch.
+ */
+class TcpTransportExecutor implements ExecutorInterface
+{
+ private $nameserver;
+ private $loop;
+ private $parser;
+ private $dumper;
+
+ /**
+ * @var ?resource
+ */
+ private $socket;
+
+ /**
+ * @var Deferred[]
+ */
+ private $pending = array();
+
+ /**
+ * @var string[]
+ */
+ private $names = array();
+
+ /**
+ * Maximum idle time when socket is current unused (i.e. no pending queries outstanding)
+ *
+ * If a new query is to be sent during the idle period, we can reuse the
+ * existing socket without having to wait for a new socket connection.
+ * This uses a rather small, hard-coded value to not keep any unneeded
+ * sockets open and to not keep the loop busy longer than needed.
+ *
+ * A future implementation may take advantage of `edns-tcp-keepalive` to keep
+ * the socket open for longer periods. This will likely require explicit
+ * configuration because this may consume additional resources and also keep
+ * the loop busy for longer than expected in some applications.
+ *
+ * @var float
+ * @link https://tools.ietf.org/html/rfc7766#section-6.2.1
+ * @link https://tools.ietf.org/html/rfc7828
+ */
+ private $idlePeriod = 0.001;
+
+ /**
+ * @var ?\React\EventLoop\TimerInterface
+ */
+ private $idleTimer;
+
+ private $writeBuffer = '';
+ private $writePending = false;
+
+ private $readBuffer = '';
+ private $readPending = false;
+
+ /** @var string */
+ private $readChunk = 0xffff;
+
+ /**
+ * @param string $nameserver
+ * @param ?LoopInterface $loop
+ */
+ public function __construct($nameserver, LoopInterface $loop = null)
+ {
+ if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) {
+ // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets
+ $nameserver = '[' . $nameserver . ']';
+ }
+
+ $parts = \parse_url((\strpos($nameserver, '://') === false ? 'tcp://' : '') . $nameserver);
+ if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'tcp' || @\inet_pton(\trim($parts['host'], '[]')) === false) {
+ throw new \InvalidArgumentException('Invalid nameserver address given');
+ }
+
+ $this->nameserver = 'tcp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53);
+ $this->loop = $loop ?: Loop::get();
+ $this->parser = new Parser();
+ $this->dumper = new BinaryDumper();
+ }
+
+ public function query(Query $query)
+ {
+ $request = Message::createRequestForQuery($query);
+
+ // keep shuffing message ID to avoid using the same message ID for two pending queries at the same time
+ while (isset($this->pending[$request->id])) {
+ $request->id = \mt_rand(0, 0xffff); // @codeCoverageIgnore
+ }
+
+ $queryData = $this->dumper->toBinary($request);
+ $length = \strlen($queryData);
+ if ($length > 0xffff) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: Query too large for TCP transport'
+ ));
+ }
+
+ $queryData = \pack('n', $length) . $queryData;
+
+ if ($this->socket === null) {
+ // create async TCP/IP connection (may take a while)
+ $socket = @\stream_socket_client($this->nameserver, $errno, $errstr, 0, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT);
+ if ($socket === false) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
+ $errno
+ ));
+ }
+
+ // set socket to non-blocking and wait for it to become writable (connection success/rejected)
+ \stream_set_blocking($socket, false);
+ if (\function_exists('stream_set_chunk_size')) {
+ \stream_set_chunk_size($socket, $this->readChunk); // @codeCoverageIgnore
+ }
+ $this->socket = $socket;
+ }
+
+ if ($this->idleTimer !== null) {
+ $this->loop->cancelTimer($this->idleTimer);
+ $this->idleTimer = null;
+ }
+
+ // wait for socket to become writable to actually write out data
+ $this->writeBuffer .= $queryData;
+ if (!$this->writePending) {
+ $this->writePending = true;
+ $this->loop->addWriteStream($this->socket, array($this, 'handleWritable'));
+ }
+
+ $names =& $this->names;
+ $that = $this;
+ $deferred = new Deferred(function () use ($that, &$names, $request) {
+ // remove from list of pending names, but remember pending query
+ $name = $names[$request->id];
+ unset($names[$request->id]);
+ $that->checkIdle();
+
+ throw new CancellationException('DNS query for ' . $name . ' has been cancelled');
+ });
+
+ $this->pending[$request->id] = $deferred;
+ $this->names[$request->id] = $query->describe();
+
+ return $deferred->promise();
+ }
+
+ /**
+ * @internal
+ */
+ public function handleWritable()
+ {
+ if ($this->readPending === false) {
+ $name = @\stream_socket_get_name($this->socket, true);
+ if ($name === false) {
+ // Connection failed? Check socket error if available for underlying errno/errstr.
+ // @codeCoverageIgnoreStart
+ if (\function_exists('socket_import_stream')) {
+ $socket = \socket_import_stream($this->socket);
+ $errno = \socket_get_option($socket, \SOL_SOCKET, \SO_ERROR);
+ $errstr = \socket_strerror($errno);
+ } else {
+ $errno = \defined('SOCKET_ECONNREFUSED') ? \SOCKET_ECONNREFUSED : 111;
+ $errstr = 'Connection refused';
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->closeError('Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')', $errno);
+ return;
+ }
+
+ $this->readPending = true;
+ $this->loop->addReadStream($this->socket, array($this, 'handleRead'));
+ }
+
+ $written = @\fwrite($this->socket, $this->writeBuffer);
+ if ($written === false || $written === 0) {
+ $error = \error_get_last();
+ \preg_match('/errno=(\d+) (.+)/', $error['message'], $m);
+ $this->closeError(
+ 'Unable to send query to DNS server ' . $this->nameserver . ' (' . (isset($m[2]) ? $m[2] : $error['message']) . ')',
+ isset($m[1]) ? (int) $m[1] : 0
+ );
+ return;
+ }
+
+ if (isset($this->writeBuffer[$written])) {
+ $this->writeBuffer = \substr($this->writeBuffer, $written);
+ } else {
+ $this->loop->removeWriteStream($this->socket);
+ $this->writePending = false;
+ $this->writeBuffer = '';
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function handleRead()
+ {
+ // read one chunk of data from the DNS server
+ // any error is fatal, this is a stream of TCP/IP data
+ $chunk = @\fread($this->socket, $this->readChunk);
+ if ($chunk === false || $chunk === '') {
+ $this->closeError('Connection to DNS server ' . $this->nameserver . ' lost');
+ return;
+ }
+
+ // reassemble complete message by concatenating all chunks.
+ $this->readBuffer .= $chunk;
+
+ // response message header contains at least 12 bytes
+ while (isset($this->readBuffer[11])) {
+ // read response message length from first 2 bytes and ensure we have length + data in buffer
+ list(, $length) = \unpack('n', $this->readBuffer);
+ if (!isset($this->readBuffer[$length + 1])) {
+ return;
+ }
+
+ $data = \substr($this->readBuffer, 2, $length);
+ $this->readBuffer = (string)substr($this->readBuffer, $length + 2);
+
+ try {
+ $response = $this->parser->parseMessage($data);
+ } catch (\Exception $e) {
+ // reject all pending queries if we received an invalid message from remote server
+ $this->closeError('Invalid message received from DNS server ' . $this->nameserver);
+ return;
+ }
+
+ // reject all pending queries if we received an unexpected response ID or truncated response
+ if (!isset($this->pending[$response->id]) || $response->tc) {
+ $this->closeError('Invalid response message received from DNS server ' . $this->nameserver);
+ return;
+ }
+
+ $deferred = $this->pending[$response->id];
+ unset($this->pending[$response->id], $this->names[$response->id]);
+
+ $deferred->resolve($response);
+
+ $this->checkIdle();
+ }
+ }
+
+ /**
+ * @internal
+ * @param string $reason
+ * @param int $code
+ */
+ public function closeError($reason, $code = 0)
+ {
+ $this->readBuffer = '';
+ if ($this->readPending) {
+ $this->loop->removeReadStream($this->socket);
+ $this->readPending = false;
+ }
+
+ $this->writeBuffer = '';
+ if ($this->writePending) {
+ $this->loop->removeWriteStream($this->socket);
+ $this->writePending = false;
+ }
+
+ if ($this->idleTimer !== null) {
+ $this->loop->cancelTimer($this->idleTimer);
+ $this->idleTimer = null;
+ }
+
+ @\fclose($this->socket);
+ $this->socket = null;
+
+ foreach ($this->names as $id => $name) {
+ $this->pending[$id]->reject(new \RuntimeException(
+ 'DNS query for ' . $name . ' failed: ' . $reason,
+ $code
+ ));
+ }
+ $this->pending = $this->names = array();
+ }
+
+ /**
+ * @internal
+ */
+ public function checkIdle()
+ {
+ if ($this->idleTimer === null && !$this->names) {
+ $that = $this;
+ $this->idleTimer = $this->loop->addTimer($this->idlePeriod, function () use ($that) {
+ $that->closeError('Idle timeout');
+ });
+ }
+ }
+}
diff --git a/vendor/react/dns/src/Query/TimeoutException.php b/vendor/react/dns/src/Query/TimeoutException.php
new file mode 100644
index 0000000..109b0a9
--- /dev/null
+++ b/vendor/react/dns/src/Query/TimeoutException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Dns\Query;
+
+final class TimeoutException extends \Exception
+{
+}
diff --git a/vendor/react/dns/src/Query/TimeoutExecutor.php b/vendor/react/dns/src/Query/TimeoutExecutor.php
new file mode 100644
index 0000000..15c8c22
--- /dev/null
+++ b/vendor/react/dns/src/Query/TimeoutExecutor.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+
+final class TimeoutExecutor implements ExecutorInterface
+{
+ private $executor;
+ private $loop;
+ private $timeout;
+
+ public function __construct(ExecutorInterface $executor, $timeout, LoopInterface $loop = null)
+ {
+ $this->executor = $executor;
+ $this->loop = $loop ?: Loop::get();
+ $this->timeout = $timeout;
+ }
+
+ public function query(Query $query)
+ {
+ return Timer\timeout($this->executor->query($query), $this->timeout, $this->loop)->then(null, function ($e) use ($query) {
+ if ($e instanceof Timer\TimeoutException) {
+ $e = new TimeoutException(sprintf("DNS query for %s timed out", $query->describe()), 0, $e);
+ }
+ throw $e;
+ });
+ }
+}
diff --git a/vendor/react/dns/src/Query/UdpTransportExecutor.php b/vendor/react/dns/src/Query/UdpTransportExecutor.php
new file mode 100644
index 0000000..4c995a8
--- /dev/null
+++ b/vendor/react/dns/src/Query/UdpTransportExecutor.php
@@ -0,0 +1,208 @@
+<?php
+
+namespace React\Dns\Query;
+
+use React\Dns\Model\Message;
+use React\Dns\Protocol\BinaryDumper;
+use React\Dns\Protocol\Parser;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Deferred;
+
+/**
+ * Send DNS queries over a UDP transport.
+ *
+ * This is the main class that sends a DNS query to your DNS server and is used
+ * internally by the `Resolver` for the actual message transport.
+ *
+ * For more advanced usages one can utilize this class directly.
+ * The following example looks up the `IPv6` address for `igor.io`.
+ *
+ * ```php
+ * $executor = new UdpTransportExecutor('8.8.8.8:53');
+ *
+ * $executor->query(
+ * new Query($name, Message::TYPE_AAAA, Message::CLASS_IN)
+ * )->then(function (Message $message) {
+ * foreach ($message->answers as $answer) {
+ * echo 'IPv6: ' . $answer->data . PHP_EOL;
+ * }
+ * }, 'printf');
+ * ```
+ *
+ * See also the [fourth example](examples).
+ *
+ * Note that this executor does not implement a timeout, so you will very likely
+ * want to use this in combination with a `TimeoutExecutor` like this:
+ *
+ * ```php
+ * $executor = new TimeoutExecutor(
+ * new UdpTransportExecutor($nameserver),
+ * 3.0
+ * );
+ * ```
+ *
+ * Also note that this executor uses an unreliable UDP transport and that it
+ * does not implement any retry logic, so you will likely want to use this in
+ * combination with a `RetryExecutor` like this:
+ *
+ * ```php
+ * $executor = new RetryExecutor(
+ * new TimeoutExecutor(
+ * new UdpTransportExecutor($nameserver),
+ * 3.0
+ * )
+ * );
+ * ```
+ *
+ * Note that this executor is entirely async and as such allows you to execute
+ * any number of queries concurrently. You should probably limit the number of
+ * concurrent queries in your application or you're very likely going to face
+ * rate limitations and bans on the resolver end. For many common applications,
+ * you may want to avoid sending the same query multiple times when the first
+ * one is still pending, so you will likely want to use this in combination with
+ * a `CoopExecutor` like this:
+ *
+ * ```php
+ * $executor = new CoopExecutor(
+ * new RetryExecutor(
+ * new TimeoutExecutor(
+ * new UdpTransportExecutor($nameserver),
+ * 3.0
+ * )
+ * )
+ * );
+ * ```
+ *
+ * > Internally, this class uses PHP's UDP sockets and does not take advantage
+ * of [react/datagram](https://github.com/reactphp/datagram) purely for
+ * organizational reasons to avoid a cyclic dependency between the two
+ * packages. Higher-level components should take advantage of the Datagram
+ * component instead of reimplementing this socket logic from scratch.
+ */
+final class UdpTransportExecutor implements ExecutorInterface
+{
+ private $nameserver;
+ private $loop;
+ private $parser;
+ private $dumper;
+
+ /**
+ * maximum UDP packet size to send and receive
+ *
+ * @var int
+ */
+ private $maxPacketSize = 512;
+
+ /**
+ * @param string $nameserver
+ * @param ?LoopInterface $loop
+ */
+ public function __construct($nameserver, LoopInterface $loop = null)
+ {
+ if (\strpos($nameserver, '[') === false && \substr_count($nameserver, ':') >= 2 && \strpos($nameserver, '://') === false) {
+ // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets
+ $nameserver = '[' . $nameserver . ']';
+ }
+
+ $parts = \parse_url((\strpos($nameserver, '://') === false ? 'udp://' : '') . $nameserver);
+ if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'udp' || @\inet_pton(\trim($parts['host'], '[]')) === false) {
+ throw new \InvalidArgumentException('Invalid nameserver address given');
+ }
+
+ $this->nameserver = 'udp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53);
+ $this->loop = $loop ?: Loop::get();
+ $this->parser = new Parser();
+ $this->dumper = new BinaryDumper();
+ }
+
+ public function query(Query $query)
+ {
+ $request = Message::createRequestForQuery($query);
+
+ $queryData = $this->dumper->toBinary($request);
+ if (isset($queryData[$this->maxPacketSize])) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: Query too large for UDP transport',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90
+ ));
+ }
+
+ // UDP connections are instant, so try connection without a loop or timeout
+ $socket = @\stream_socket_client($this->nameserver, $errno, $errstr, 0);
+ if ($socket === false) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: Unable to connect to DNS server ' . $this->nameserver . ' (' . $errstr . ')',
+ $errno
+ ));
+ }
+
+ // set socket to non-blocking and immediately try to send (fill write buffer)
+ \stream_set_blocking($socket, false);
+ $written = @\fwrite($socket, $queryData);
+
+ if ($written !== \strlen($queryData)) {
+ // Write may potentially fail, but most common errors are already caught by connection check above.
+ // Among others, macOS is known to report here when trying to send to broadcast address.
+ // This can also be reproduced by writing data exceeding `stream_set_chunk_size()` to a server refusing UDP data.
+ // fwrite(): send of 8192 bytes failed with errno=111 Connection refused
+ $error = \error_get_last();
+ \preg_match('/errno=(\d+) (.+)/', $error['message'], $m);
+ return \React\Promise\reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: Unable to send query to DNS server ' . $this->nameserver . ' (' . (isset($m[2]) ? $m[2] : $error['message']) . ')',
+ isset($m[1]) ? (int) $m[1] : 0
+ ));
+ }
+
+ $loop = $this->loop;
+ $deferred = new Deferred(function () use ($loop, $socket, $query) {
+ // cancellation should remove socket from loop and close socket
+ $loop->removeReadStream($socket);
+ \fclose($socket);
+
+ throw new CancellationException('DNS query for ' . $query->describe() . ' has been cancelled');
+ });
+
+ $max = $this->maxPacketSize;
+ $parser = $this->parser;
+ $nameserver = $this->nameserver;
+ $loop->addReadStream($socket, function ($socket) use ($loop, $deferred, $query, $parser, $request, $max, $nameserver) {
+ // try to read a single data packet from the DNS server
+ // ignoring any errors, this is uses UDP packets and not a stream of data
+ $data = @\fread($socket, $max);
+ if ($data === false) {
+ return;
+ }
+
+ try {
+ $response = $parser->parseMessage($data);
+ } catch (\Exception $e) {
+ // ignore and await next if we received an invalid message from remote server
+ // this may as well be a fake response from an attacker (possible DOS)
+ return;
+ }
+
+ // ignore and await next if we received an unexpected response ID
+ // this may as well be a fake response from an attacker (possible cache poisoning)
+ if ($response->id !== $request->id) {
+ return;
+ }
+
+ // we only react to the first valid message, so remove socket from loop and close
+ $loop->removeReadStream($socket);
+ \fclose($socket);
+
+ if ($response->tc) {
+ $deferred->reject(new \RuntimeException(
+ 'DNS query for ' . $query->describe() . ' failed: The DNS server ' . $nameserver . ' returned a truncated result for a UDP query',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 90
+ ));
+ return;
+ }
+
+ $deferred->resolve($response);
+ });
+
+ return $deferred->promise();
+ }
+}
diff --git a/vendor/react/dns/src/RecordNotFoundException.php b/vendor/react/dns/src/RecordNotFoundException.php
new file mode 100644
index 0000000..3b70274
--- /dev/null
+++ b/vendor/react/dns/src/RecordNotFoundException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Dns;
+
+final class RecordNotFoundException extends \Exception
+{
+}
diff --git a/vendor/react/dns/src/Resolver/Factory.php b/vendor/react/dns/src/Resolver/Factory.php
new file mode 100644
index 0000000..5fe608c
--- /dev/null
+++ b/vendor/react/dns/src/Resolver/Factory.php
@@ -0,0 +1,214 @@
+<?php
+
+namespace React\Dns\Resolver;
+
+use React\Cache\ArrayCache;
+use React\Cache\CacheInterface;
+use React\Dns\Config\Config;
+use React\Dns\Config\HostsFile;
+use React\Dns\Query\CachingExecutor;
+use React\Dns\Query\CoopExecutor;
+use React\Dns\Query\ExecutorInterface;
+use React\Dns\Query\FallbackExecutor;
+use React\Dns\Query\HostsFileExecutor;
+use React\Dns\Query\RetryExecutor;
+use React\Dns\Query\SelectiveTransportExecutor;
+use React\Dns\Query\TcpTransportExecutor;
+use React\Dns\Query\TimeoutExecutor;
+use React\Dns\Query\UdpTransportExecutor;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+
+final class Factory
+{
+ /**
+ * Creates a DNS resolver instance for the given DNS config
+ *
+ * As of v1.7.0 it's recommended to pass a `Config` object instead of a
+ * single nameserver address. If the given config contains more than one DNS
+ * nameserver, all DNS nameservers will be used in order. The primary DNS
+ * server will always be used first before falling back to the secondary or
+ * tertiary DNS server.
+ *
+ * @param Config|string $config DNS Config object (recommended) or single nameserver address
+ * @param ?LoopInterface $loop
+ * @return \React\Dns\Resolver\ResolverInterface
+ * @throws \InvalidArgumentException for invalid DNS server address
+ * @throws \UnderflowException when given DNS Config object has an empty list of nameservers
+ */
+ public function create($config, LoopInterface $loop = null)
+ {
+ $executor = $this->decorateHostsFileExecutor($this->createExecutor($config, $loop ?: Loop::get()));
+
+ return new Resolver($executor);
+ }
+
+ /**
+ * Creates a cached DNS resolver instance for the given DNS config and cache
+ *
+ * As of v1.7.0 it's recommended to pass a `Config` object instead of a
+ * single nameserver address. If the given config contains more than one DNS
+ * nameserver, all DNS nameservers will be used in order. The primary DNS
+ * server will always be used first before falling back to the secondary or
+ * tertiary DNS server.
+ *
+ * @param Config|string $config DNS Config object (recommended) or single nameserver address
+ * @param ?LoopInterface $loop
+ * @param ?CacheInterface $cache
+ * @return \React\Dns\Resolver\ResolverInterface
+ * @throws \InvalidArgumentException for invalid DNS server address
+ * @throws \UnderflowException when given DNS Config object has an empty list of nameservers
+ */
+ public function createCached($config, LoopInterface $loop = null, CacheInterface $cache = null)
+ {
+ // default to keeping maximum of 256 responses in cache unless explicitly given
+ if (!($cache instanceof CacheInterface)) {
+ $cache = new ArrayCache(256);
+ }
+
+ $executor = $this->createExecutor($config, $loop ?: Loop::get());
+ $executor = new CachingExecutor($executor, $cache);
+ $executor = $this->decorateHostsFileExecutor($executor);
+
+ return new Resolver($executor);
+ }
+
+ /**
+ * Tries to load the hosts file and decorates the given executor on success
+ *
+ * @param ExecutorInterface $executor
+ * @return ExecutorInterface
+ * @codeCoverageIgnore
+ */
+ private function decorateHostsFileExecutor(ExecutorInterface $executor)
+ {
+ try {
+ $executor = new HostsFileExecutor(
+ HostsFile::loadFromPathBlocking(),
+ $executor
+ );
+ } catch (\RuntimeException $e) {
+ // ignore this file if it can not be loaded
+ }
+
+ // Windows does not store localhost in hosts file by default but handles this internally
+ // To compensate for this, we explicitly use hard-coded defaults for localhost
+ if (DIRECTORY_SEPARATOR === '\\') {
+ $executor = new HostsFileExecutor(
+ new HostsFile("127.0.0.1 localhost\n::1 localhost"),
+ $executor
+ );
+ }
+
+ return $executor;
+ }
+
+ /**
+ * @param Config|string $nameserver
+ * @param LoopInterface $loop
+ * @return CoopExecutor
+ * @throws \InvalidArgumentException for invalid DNS server address
+ * @throws \UnderflowException when given DNS Config object has an empty list of nameservers
+ */
+ private function createExecutor($nameserver, LoopInterface $loop)
+ {
+ if ($nameserver instanceof Config) {
+ if (!$nameserver->nameservers) {
+ throw new \UnderflowException('Empty config with no DNS servers');
+ }
+
+ // Hard-coded to check up to 3 DNS servers to match default limits in place in most systems (see MAXNS config).
+ // Note to future self: Recursion isn't too hard, but how deep do we really want to go?
+ $primary = reset($nameserver->nameservers);
+ $secondary = next($nameserver->nameservers);
+ $tertiary = next($nameserver->nameservers);
+
+ if ($tertiary !== false) {
+ // 3 DNS servers given => nest first with fallback for second and third
+ return new CoopExecutor(
+ new RetryExecutor(
+ new FallbackExecutor(
+ $this->createSingleExecutor($primary, $loop),
+ new FallbackExecutor(
+ $this->createSingleExecutor($secondary, $loop),
+ $this->createSingleExecutor($tertiary, $loop)
+ )
+ )
+ )
+ );
+ } elseif ($secondary !== false) {
+ // 2 DNS servers given => fallback from first to second
+ return new CoopExecutor(
+ new RetryExecutor(
+ new FallbackExecutor(
+ $this->createSingleExecutor($primary, $loop),
+ $this->createSingleExecutor($secondary, $loop)
+ )
+ )
+ );
+ } else {
+ // 1 DNS server given => use single executor
+ $nameserver = $primary;
+ }
+ }
+
+ return new CoopExecutor(new RetryExecutor($this->createSingleExecutor($nameserver, $loop)));
+ }
+
+ /**
+ * @param string $nameserver
+ * @param LoopInterface $loop
+ * @return ExecutorInterface
+ * @throws \InvalidArgumentException for invalid DNS server address
+ */
+ private function createSingleExecutor($nameserver, LoopInterface $loop)
+ {
+ $parts = \parse_url($nameserver);
+
+ if (isset($parts['scheme']) && $parts['scheme'] === 'tcp') {
+ $executor = $this->createTcpExecutor($nameserver, $loop);
+ } elseif (isset($parts['scheme']) && $parts['scheme'] === 'udp') {
+ $executor = $this->createUdpExecutor($nameserver, $loop);
+ } else {
+ $executor = new SelectiveTransportExecutor(
+ $this->createUdpExecutor($nameserver, $loop),
+ $this->createTcpExecutor($nameserver, $loop)
+ );
+ }
+
+ return $executor;
+ }
+
+ /**
+ * @param string $nameserver
+ * @param LoopInterface $loop
+ * @return TimeoutExecutor
+ * @throws \InvalidArgumentException for invalid DNS server address
+ */
+ private function createTcpExecutor($nameserver, LoopInterface $loop)
+ {
+ return new TimeoutExecutor(
+ new TcpTransportExecutor($nameserver, $loop),
+ 5.0,
+ $loop
+ );
+ }
+
+ /**
+ * @param string $nameserver
+ * @param LoopInterface $loop
+ * @return TimeoutExecutor
+ * @throws \InvalidArgumentException for invalid DNS server address
+ */
+ private function createUdpExecutor($nameserver, LoopInterface $loop)
+ {
+ return new TimeoutExecutor(
+ new UdpTransportExecutor(
+ $nameserver,
+ $loop
+ ),
+ 5.0,
+ $loop
+ );
+ }
+}
diff --git a/vendor/react/dns/src/Resolver/Resolver.php b/vendor/react/dns/src/Resolver/Resolver.php
new file mode 100644
index 0000000..92926f3
--- /dev/null
+++ b/vendor/react/dns/src/Resolver/Resolver.php
@@ -0,0 +1,147 @@
+<?php
+
+namespace React\Dns\Resolver;
+
+use React\Dns\Model\Message;
+use React\Dns\Query\ExecutorInterface;
+use React\Dns\Query\Query;
+use React\Dns\RecordNotFoundException;
+
+/**
+ * @see ResolverInterface for the base interface
+ */
+final class Resolver implements ResolverInterface
+{
+ private $executor;
+
+ public function __construct(ExecutorInterface $executor)
+ {
+ $this->executor = $executor;
+ }
+
+ public function resolve($domain)
+ {
+ return $this->resolveAll($domain, Message::TYPE_A)->then(function (array $ips) {
+ return $ips[array_rand($ips)];
+ });
+ }
+
+ public function resolveAll($domain, $type)
+ {
+ $query = new Query($domain, $type, Message::CLASS_IN);
+ $that = $this;
+
+ return $this->executor->query(
+ $query
+ )->then(function (Message $response) use ($query, $that) {
+ return $that->extractValues($query, $response);
+ });
+ }
+
+ /**
+ * [Internal] extract all resource record values from response for this query
+ *
+ * @param Query $query
+ * @param Message $response
+ * @return array
+ * @throws RecordNotFoundException when response indicates an error or contains no data
+ * @internal
+ */
+ public function extractValues(Query $query, Message $response)
+ {
+ // reject if response code indicates this is an error response message
+ $code = $response->rcode;
+ if ($code !== Message::RCODE_OK) {
+ switch ($code) {
+ case Message::RCODE_FORMAT_ERROR:
+ $message = 'Format Error';
+ break;
+ case Message::RCODE_SERVER_FAILURE:
+ $message = 'Server Failure';
+ break;
+ case Message::RCODE_NAME_ERROR:
+ $message = 'Non-Existent Domain / NXDOMAIN';
+ break;
+ case Message::RCODE_NOT_IMPLEMENTED:
+ $message = 'Not Implemented';
+ break;
+ case Message::RCODE_REFUSED:
+ $message = 'Refused';
+ break;
+ default:
+ $message = 'Unknown error response code ' . $code;
+ }
+ throw new RecordNotFoundException(
+ 'DNS query for ' . $query->describe() . ' returned an error response (' . $message . ')',
+ $code
+ );
+ }
+
+ $answers = $response->answers;
+ $addresses = $this->valuesByNameAndType($answers, $query->name, $query->type);
+
+ // reject if we did not receive a valid answer (domain is valid, but no record for this type could be found)
+ if (0 === count($addresses)) {
+ throw new RecordNotFoundException(
+ 'DNS query for ' . $query->describe() . ' did not return a valid answer (NOERROR / NODATA)'
+ );
+ }
+
+ return array_values($addresses);
+ }
+
+ /**
+ * @param \React\Dns\Model\Record[] $answers
+ * @param string $name
+ * @param int $type
+ * @return array
+ */
+ private function valuesByNameAndType(array $answers, $name, $type)
+ {
+ // return all record values for this name and type (if any)
+ $named = $this->filterByName($answers, $name);
+ $records = $this->filterByType($named, $type);
+ if ($records) {
+ return $this->mapRecordData($records);
+ }
+
+ // no matching records found? check if there are any matching CNAMEs instead
+ $cnameRecords = $this->filterByType($named, Message::TYPE_CNAME);
+ if ($cnameRecords) {
+ $cnames = $this->mapRecordData($cnameRecords);
+ foreach ($cnames as $cname) {
+ $records = array_merge(
+ $records,
+ $this->valuesByNameAndType($answers, $cname, $type)
+ );
+ }
+ }
+
+ return $records;
+ }
+
+ private function filterByName(array $answers, $name)
+ {
+ return $this->filterByField($answers, 'name', $name);
+ }
+
+ private function filterByType(array $answers, $type)
+ {
+ return $this->filterByField($answers, 'type', $type);
+ }
+
+ private function filterByField(array $answers, $field, $value)
+ {
+ $value = strtolower($value);
+ return array_filter($answers, function ($answer) use ($field, $value) {
+ return $value === strtolower($answer->$field);
+ });
+ }
+
+ private function mapRecordData(array $records)
+ {
+ return array_map(function ($record) {
+ return $record->data;
+ }, $records);
+ }
+}
diff --git a/vendor/react/dns/src/Resolver/ResolverInterface.php b/vendor/react/dns/src/Resolver/ResolverInterface.php
new file mode 100644
index 0000000..fe937dc
--- /dev/null
+++ b/vendor/react/dns/src/Resolver/ResolverInterface.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace React\Dns\Resolver;
+
+interface ResolverInterface
+{
+ /**
+ * Resolves the given $domain name to a single IPv4 address (type `A` query).
+ *
+ * ```php
+ * $resolver->resolve('reactphp.org')->then(function ($ip) {
+ * echo 'IP for reactphp.org is ' . $ip . PHP_EOL;
+ * });
+ * ```
+ *
+ * This is one of the main methods in this package. It sends a DNS query
+ * for the given $domain name to your DNS server and returns a single IP
+ * address on success.
+ *
+ * If the DNS server sends a DNS response message that contains more than
+ * one IP address for this query, it will randomly pick one of the IP
+ * addresses from the response. If you want the full list of IP addresses
+ * or want to send a different type of query, you should use the
+ * [`resolveAll()`](#resolveall) method instead.
+ *
+ * If the DNS server sends a DNS response message that indicates an error
+ * code, this method will reject with a `RecordNotFoundException`. Its
+ * message and code can be used to check for the response code.
+ *
+ * If the DNS communication fails and the server does not respond with a
+ * valid response message, this message will reject with an `Exception`.
+ *
+ * Pending DNS queries can be cancelled by cancelling its pending promise like so:
+ *
+ * ```php
+ * $promise = $resolver->resolve('reactphp.org');
+ *
+ * $promise->cancel();
+ * ```
+ *
+ * @param string $domain
+ * @return \React\Promise\PromiseInterface<string,\Exception>
+ * resolves with a single IP address on success or rejects with an Exception on error.
+ */
+ public function resolve($domain);
+
+ /**
+ * Resolves all record values for the given $domain name and query $type.
+ *
+ * ```php
+ * $resolver->resolveAll('reactphp.org', Message::TYPE_A)->then(function ($ips) {
+ * echo 'IPv4 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL;
+ * });
+ *
+ * $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA)->then(function ($ips) {
+ * echo 'IPv6 addresses for reactphp.org ' . implode(', ', $ips) . PHP_EOL;
+ * });
+ * ```
+ *
+ * This is one of the main methods in this package. It sends a DNS query
+ * for the given $domain name to your DNS server and returns a list with all
+ * record values on success.
+ *
+ * If the DNS server sends a DNS response message that contains one or more
+ * records for this query, it will return a list with all record values
+ * from the response. You can use the `Message::TYPE_*` constants to control
+ * which type of query will be sent. Note that this method always returns a
+ * list of record values, but each record value type depends on the query
+ * type. For example, it returns the IPv4 addresses for type `A` queries,
+ * the IPv6 addresses for type `AAAA` queries, the hostname for type `NS`,
+ * `CNAME` and `PTR` queries and structured data for other queries. See also
+ * the `Record` documentation for more details.
+ *
+ * If the DNS server sends a DNS response message that indicates an error
+ * code, this method will reject with a `RecordNotFoundException`. Its
+ * message and code can be used to check for the response code.
+ *
+ * If the DNS communication fails and the server does not respond with a
+ * valid response message, this message will reject with an `Exception`.
+ *
+ * Pending DNS queries can be cancelled by cancelling its pending promise like so:
+ *
+ * ```php
+ * $promise = $resolver->resolveAll('reactphp.org', Message::TYPE_AAAA);
+ *
+ * $promise->cancel();
+ * ```
+ *
+ * @param string $domain
+ * @return \React\Promise\PromiseInterface<array,\Exception>
+ * Resolves with all record values on success or rejects with an Exception on error.
+ */
+ public function resolveAll($domain, $type);
+}
diff --git a/vendor/react/event-loop/LICENSE b/vendor/react/event-loop/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/event-loop/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/event-loop/composer.json b/vendor/react/event-loop/composer.json
new file mode 100644
index 0000000..d9b032e
--- /dev/null
+++ b/vendor/react/event-loop/composer.json
@@ -0,0 +1,49 @@
+{
+ "name": "react/event-loop",
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": ["event-loop", "asynchronous"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "suggest": {
+ "ext-event": "~1.0 for ExtEventLoop",
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop",
+ "ext-uv": "* for ExtUvLoop"
+ },
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Tests\\EventLoop\\": "tests"
+ }
+ }
+}
diff --git a/vendor/react/event-loop/src/ExtEvLoop.php b/vendor/react/event-loop/src/ExtEvLoop.php
new file mode 100644
index 0000000..a3fcec6
--- /dev/null
+++ b/vendor/react/event-loop/src/ExtEvLoop.php
@@ -0,0 +1,253 @@
+<?php
+
+namespace React\EventLoop;
+
+use Ev;
+use EvIo;
+use EvLoop;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-ev` based event loop.
+ *
+ * This loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev),
+ * that provides an interface to `libev` library.
+ * `libev` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This loop is known to work with PHP 5.4 through PHP 8+.
+ *
+ * @see http://php.net/manual/en/book.ev.php
+ * @see https://bitbucket.org/osmanov/pecl-ev/overview
+ */
+class ExtEvLoop implements LoopInterface
+{
+ /**
+ * @var EvLoop
+ */
+ private $loop;
+
+ /**
+ * @var FutureTickQueue
+ */
+ private $futureTickQueue;
+
+ /**
+ * @var SplObjectStorage
+ */
+ private $timers;
+
+ /**
+ * @var EvIo[]
+ */
+ private $readStreams = array();
+
+ /**
+ * @var EvIo[]
+ */
+ private $writeStreams = array();
+
+ /**
+ * @var bool
+ */
+ private $running;
+
+ /**
+ * @var SignalsHandler
+ */
+ private $signals;
+
+ /**
+ * @var \EvSignal[]
+ */
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ $this->loop = new EvLoop();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timers = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int)$stream;
+
+ if (isset($this->readStreams[$key])) {
+ return;
+ }
+
+ $callback = $this->getStreamListenerClosure($stream, $listener);
+ $event = $this->loop->io($stream, Ev::READ, $callback);
+ $this->readStreams[$key] = $event;
+ }
+
+ /**
+ * @param resource $stream
+ * @param callable $listener
+ *
+ * @return \Closure
+ */
+ private function getStreamListenerClosure($stream, $listener)
+ {
+ return function () use ($stream, $listener) {
+ \call_user_func($listener, $stream);
+ };
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int)$stream;
+
+ if (isset($this->writeStreams[$key])) {
+ return;
+ }
+
+ $callback = $this->getStreamListenerClosure($stream, $listener);
+ $event = $this->loop->io($stream, Ev::WRITE, $callback);
+ $this->writeStreams[$key] = $event;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int)$stream;
+
+ if (!isset($this->readStreams[$key])) {
+ return;
+ }
+
+ $this->readStreams[$key]->stop();
+ unset($this->readStreams[$key]);
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int)$stream;
+
+ if (!isset($this->writeStreams[$key])) {
+ return;
+ }
+
+ $this->writeStreams[$key]->stop();
+ unset($this->writeStreams[$key]);
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $that = $this;
+ $timers = $this->timers;
+ $callback = function () use ($timer, $timers, $that) {
+ \call_user_func($timer->getCallback(), $timer);
+
+ if ($timers->contains($timer)) {
+ $that->cancelTimer($timer);
+ }
+ };
+
+ $event = $this->loop->timer($timer->getInterval(), 0.0, $callback);
+ $this->timers->attach($timer, $event);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $callback = function () use ($timer) {
+ \call_user_func($timer->getCallback(), $timer);
+ };
+
+ $event = $this->loop->timer($timer->getInterval(), $timer->getInterval(), $callback);
+ $this->timers->attach($timer, $event);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if (!isset($this->timers[$timer])) {
+ return;
+ }
+
+ $event = $this->timers[$timer];
+ $event->stop();
+ $this->timers->detach($timer);
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
+ $wasJustStopped = !$this->running;
+ $nothingLeftToDo = !$this->readStreams
+ && !$this->writeStreams
+ && !$this->timers->count()
+ && $this->signals->isEmpty();
+
+ $flags = Ev::RUN_ONCE;
+ if ($wasJustStopped || $hasPendingCallbacks) {
+ $flags |= Ev::RUN_NOWAIT;
+ } elseif ($nothingLeftToDo) {
+ break;
+ }
+
+ $this->loop->run($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ public function __destruct()
+ {
+ /** @var TimerInterface $timer */
+ foreach ($this->timers as $timer) {
+ $this->cancelTimer($timer);
+ }
+
+ foreach ($this->readStreams as $key => $stream) {
+ $this->removeReadStream($key);
+ }
+
+ foreach ($this->writeStreams as $key => $stream) {
+ $this->removeWriteStream($key);
+ }
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = $this->loop->signal($signal, function() use ($signal) {
+ $this->signals->call($signal);
+ });
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal]->stop();
+ unset($this->signalEvents[$signal]);
+ }
+ }
+}
diff --git a/vendor/react/event-loop/src/ExtEventLoop.php b/vendor/react/event-loop/src/ExtEventLoop.php
new file mode 100644
index 0000000..b162a40
--- /dev/null
+++ b/vendor/react/event-loop/src/ExtEventLoop.php
@@ -0,0 +1,275 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use Event;
+use EventBase;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-event` based event loop.
+ *
+ * This uses the [`event` PECL extension](https://pecl.php.net/package/event),
+ * that provides an interface to `libevent` library.
+ * `libevent` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This loop is known to work with PHP 5.4 through PHP 8+.
+ *
+ * @link https://pecl.php.net/package/event
+ */
+final class ExtEventLoop implements LoopInterface
+{
+ private $eventBase;
+ private $futureTickQueue;
+ private $timerCallback;
+ private $timerEvents;
+ private $streamCallback;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $readListeners = array();
+ private $writeListeners = array();
+ private $readRefs = array();
+ private $writeRefs = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!\class_exists('EventBase', false)) {
+ throw new BadMethodCallException('Cannot create ExtEventLoop, ext-event extension missing');
+ }
+
+ // support arbitrary file descriptors and not just sockets
+ // Windows only has limited file descriptor support, so do not require this (will fail otherwise)
+ // @link http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html#_setting_up_a_complicated_event_base
+ $config = new \EventConfig();
+ if (\DIRECTORY_SEPARATOR !== '\\') {
+ $config->requireFeatures(\EventConfig::FEATURE_FDS);
+ }
+
+ $this->eventBase = new EventBase($config);
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+
+ $this->createTimerCallback();
+ $this->createStreamCallback();
+ }
+
+ public function __destruct()
+ {
+ // explicitly clear all references to Event objects to prevent SEGFAULTs on Windows
+ foreach ($this->timerEvents as $timer) {
+ $this->timerEvents->detach($timer);
+ }
+
+ $this->readEvents = array();
+ $this->writeEvents = array();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->readListeners[$key])) {
+ return;
+ }
+
+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::READ, $this->streamCallback);
+ $event->add();
+ $this->readEvents[$key] = $event;
+ $this->readListeners[$key] = $listener;
+
+ // ext-event does not increase refcount on stream resources for PHP 7+
+ // manually keep track of stream resource to prevent premature garbage collection
+ if (\PHP_VERSION_ID >= 70000) {
+ $this->readRefs[$key] = $stream;
+ }
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->writeListeners[$key])) {
+ return;
+ }
+
+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::WRITE, $this->streamCallback);
+ $event->add();
+ $this->writeEvents[$key] = $event;
+ $this->writeListeners[$key] = $listener;
+
+ // ext-event does not increase refcount on stream resources for PHP 7+
+ // manually keep track of stream resource to prevent premature garbage collection
+ if (\PHP_VERSION_ID >= 70000) {
+ $this->writeRefs[$key] = $stream;
+ }
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readEvents[$key])) {
+ $this->readEvents[$key]->free();
+ unset(
+ $this->readEvents[$key],
+ $this->readListeners[$key],
+ $this->readRefs[$key]
+ );
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeEvents[$key])) {
+ $this->writeEvents[$key]->free();
+ unset(
+ $this->writeEvents[$key],
+ $this->writeListeners[$key],
+ $this->writeRefs[$key]
+ );
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if ($this->timerEvents->contains($timer)) {
+ $this->timerEvents[$timer]->free();
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = Event::signal($this->eventBase, $signal, array($this->signals, 'call'));
+ $this->signalEvents[$signal]->add();
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ $this->signalEvents[$signal]->free();
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = EventBase::LOOP_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= EventBase::LOOP_NONBLOCK;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ $this->eventBase->loop($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Schedule a timer for execution.
+ *
+ * @param TimerInterface $timer
+ */
+ private function scheduleTimer(TimerInterface $timer)
+ {
+ $flags = Event::TIMEOUT;
+
+ if ($timer->isPeriodic()) {
+ $flags |= Event::PERSIST;
+ }
+
+ $event = new Event($this->eventBase, -1, $flags, $this->timerCallback, $timer);
+ $this->timerEvents[$timer] = $event;
+
+ $event->add($timer->getInterval());
+ }
+
+ /**
+ * Create a callback used as the target of timer events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createTimerCallback()
+ {
+ $timers = $this->timerEvents;
+ $this->timerCallback = function ($_, $__, $timer) use ($timers) {
+ \call_user_func($timer->getCallback(), $timer);
+
+ if (!$timer->isPeriodic() && $timers->contains($timer)) {
+ $this->cancelTimer($timer);
+ }
+ };
+ }
+
+ /**
+ * Create a callback used as the target of stream events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createStreamCallback()
+ {
+ $read =& $this->readListeners;
+ $write =& $this->writeListeners;
+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
+ $key = (int) $stream;
+
+ if (Event::READ === (Event::READ & $flags) && isset($read[$key])) {
+ \call_user_func($read[$key], $stream);
+ }
+
+ if (Event::WRITE === (Event::WRITE & $flags) && isset($write[$key])) {
+ \call_user_func($write[$key], $stream);
+ }
+ };
+ }
+}
diff --git a/vendor/react/event-loop/src/ExtLibevLoop.php b/vendor/react/event-loop/src/ExtLibevLoop.php
new file mode 100644
index 0000000..c303fdd
--- /dev/null
+++ b/vendor/react/event-loop/src/ExtLibevLoop.php
@@ -0,0 +1,201 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use libev\EventLoop;
+use libev\IOEvent;
+use libev\SignalEvent;
+use libev\TimerEvent;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * [Deprecated] An `ext-libev` based event loop.
+ *
+ * This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev),
+ * that provides an interface to `libev` library.
+ * `libev` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This loop does only work with PHP 5.
+ * An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
+ * to happen any time soon.
+ *
+ * @see https://github.com/m4rw3r/php-libev
+ * @see https://gist.github.com/1688204
+ * @deprecated 1.2.0, use [`ExtEvLoop`](#extevloop) instead.
+ */
+final class ExtLibevLoop implements LoopInterface
+{
+ private $loop;
+ private $futureTickQueue;
+ private $timerEvents;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!\class_exists('libev\EventLoop', false)) {
+ throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing');
+ }
+
+ $this->loop = new EventLoop();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ if (isset($this->readEvents[(int) $stream])) {
+ return;
+ }
+
+ $callback = function () use ($stream, $listener) {
+ \call_user_func($listener, $stream);
+ };
+
+ $event = new IOEvent($callback, $stream, IOEvent::READ);
+ $this->loop->add($event);
+
+ $this->readEvents[(int) $stream] = $event;
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ if (isset($this->writeEvents[(int) $stream])) {
+ return;
+ }
+
+ $callback = function () use ($stream, $listener) {
+ \call_user_func($listener, $stream);
+ };
+
+ $event = new IOEvent($callback, $stream, IOEvent::WRITE);
+ $this->loop->add($event);
+
+ $this->writeEvents[(int) $stream] = $event;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readEvents[$key])) {
+ $this->readEvents[$key]->stop();
+ $this->loop->remove($this->readEvents[$key]);
+ unset($this->readEvents[$key]);
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeEvents[$key])) {
+ $this->writeEvents[$key]->stop();
+ $this->loop->remove($this->writeEvents[$key]);
+ unset($this->writeEvents[$key]);
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer( $interval, $callback, false);
+
+ $that = $this;
+ $timers = $this->timerEvents;
+ $callback = function () use ($timer, $timers, $that) {
+ \call_user_func($timer->getCallback(), $timer);
+
+ if ($timers->contains($timer)) {
+ $that->cancelTimer($timer);
+ }
+ };
+
+ $event = new TimerEvent($callback, $timer->getInterval());
+ $this->timerEvents->attach($timer, $event);
+ $this->loop->add($event);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $callback = function () use ($timer) {
+ \call_user_func($timer->getCallback(), $timer);
+ };
+
+ $event = new TimerEvent($callback, $timer->getInterval(), $timer->getInterval());
+ $this->timerEvents->attach($timer, $event);
+ $this->loop->add($event);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if (isset($this->timerEvents[$timer])) {
+ $this->loop->remove($this->timerEvents[$timer]);
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $signals = $this->signals;
+ $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) {
+ $signals->call($signal);
+ }, $signal);
+ $this->loop->add($this->signalEvents[$signal]);
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ $this->signalEvents[$signal]->stop();
+ $this->loop->remove($this->signalEvents[$signal]);
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = EventLoop::RUN_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= EventLoop::RUN_NOWAIT;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ $this->loop->run($flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+}
diff --git a/vendor/react/event-loop/src/ExtLibeventLoop.php b/vendor/react/event-loop/src/ExtLibeventLoop.php
new file mode 100644
index 0000000..099293a
--- /dev/null
+++ b/vendor/react/event-loop/src/ExtLibeventLoop.php
@@ -0,0 +1,285 @@
+<?php
+
+namespace React\EventLoop;
+
+use BadMethodCallException;
+use Event;
+use EventBase;
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * [Deprecated] An `ext-libevent` based event loop.
+ *
+ * This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent),
+ * that provides an interface to `libevent` library.
+ * `libevent` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This event loop does only work with PHP 5.
+ * An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for
+ * PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s.
+ * To reiterate: Using this event loop on PHP 7 is not recommended.
+ * Accordingly, neither the [`Loop` class](#loop) nor the deprecated
+ * [`Factory` class](#factory) will try to use this event loop on PHP 7.
+ *
+ * This event loop is known to trigger a readable listener only if
+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
+ * stream has already been readable from the beginning.
+ * This also implies that a stream may not be recognized as readable when data
+ * is still left in PHP's internal stream buffers.
+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
+ * to disable PHP's internal read buffer in this case.
+ * See also [`addReadStream()`](#addreadstream) for more details.
+ *
+ * @link https://pecl.php.net/package/libevent
+ * @deprecated 1.2.0, use [`ExtEventLoop`](#exteventloop) instead.
+ */
+final class ExtLibeventLoop implements LoopInterface
+{
+ /** @internal */
+ const MICROSECONDS_PER_SECOND = 1000000;
+
+ private $eventBase;
+ private $futureTickQueue;
+ private $timerCallback;
+ private $timerEvents;
+ private $streamCallback;
+ private $readEvents = array();
+ private $writeEvents = array();
+ private $readListeners = array();
+ private $writeListeners = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+
+ public function __construct()
+ {
+ if (!\function_exists('event_base_new')) {
+ throw new BadMethodCallException('Cannot create ExtLibeventLoop, ext-libevent extension missing');
+ }
+
+ $this->eventBase = \event_base_new();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timerEvents = new SplObjectStorage();
+ $this->signals = new SignalsHandler();
+
+ $this->createTimerCallback();
+ $this->createStreamCallback();
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->readListeners[$key])) {
+ return;
+ }
+
+ $event = \event_new();
+ \event_set($event, $stream, \EV_PERSIST | \EV_READ, $this->streamCallback);
+ \event_base_set($event, $this->eventBase);
+ \event_add($event);
+
+ $this->readEvents[$key] = $event;
+ $this->readListeners[$key] = $listener;
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+ if (isset($this->writeListeners[$key])) {
+ return;
+ }
+
+ $event = \event_new();
+ \event_set($event, $stream, \EV_PERSIST | \EV_WRITE, $this->streamCallback);
+ \event_base_set($event, $this->eventBase);
+ \event_add($event);
+
+ $this->writeEvents[$key] = $event;
+ $this->writeListeners[$key] = $listener;
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->readListeners[$key])) {
+ $event = $this->readEvents[$key];
+ \event_del($event);
+ \event_free($event);
+
+ unset(
+ $this->readEvents[$key],
+ $this->readListeners[$key]
+ );
+ }
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ if (isset($this->writeListeners[$key])) {
+ $event = $this->writeEvents[$key];
+ \event_del($event);
+ \event_free($event);
+
+ unset(
+ $this->writeEvents[$key],
+ $this->writeListeners[$key]
+ );
+ }
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->scheduleTimer($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if ($this->timerEvents->contains($timer)) {
+ $event = $this->timerEvents[$timer];
+ \event_del($event);
+ \event_free($event);
+
+ $this->timerEvents->detach($timer);
+ }
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $this->signalEvents[$signal] = \event_new();
+ \event_set($this->signalEvents[$signal], $signal, \EV_PERSIST | \EV_SIGNAL, array($this->signals, 'call'));
+ \event_base_set($this->signalEvents[$signal], $this->eventBase);
+ \event_add($this->signalEvents[$signal]);
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ \event_del($this->signalEvents[$signal]);
+ \event_free($this->signalEvents[$signal]);
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $flags = \EVLOOP_ONCE;
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $flags |= \EVLOOP_NONBLOCK;
+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
+ break;
+ }
+
+ \event_base_loop($this->eventBase, $flags);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Schedule a timer for execution.
+ *
+ * @param TimerInterface $timer
+ */
+ private function scheduleTimer(TimerInterface $timer)
+ {
+ $this->timerEvents[$timer] = $event = \event_timer_new();
+
+ \event_timer_set($event, $this->timerCallback, $timer);
+ \event_base_set($event, $this->eventBase);
+ \event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND);
+ }
+
+ /**
+ * Create a callback used as the target of timer events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createTimerCallback()
+ {
+ $that = $this;
+ $timers = $this->timerEvents;
+ $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) {
+ \call_user_func($timer->getCallback(), $timer);
+
+ // Timer already cancelled ...
+ if (!$timers->contains($timer)) {
+ return;
+ }
+
+ // Reschedule periodic timers ...
+ if ($timer->isPeriodic()) {
+ \event_add(
+ $timers[$timer],
+ $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND
+ );
+
+ // Clean-up one shot timers ...
+ } else {
+ $that->cancelTimer($timer);
+ }
+ };
+ }
+
+ /**
+ * Create a callback used as the target of stream events.
+ *
+ * A reference is kept to the callback for the lifetime of the loop
+ * to prevent "Cannot destroy active lambda function" fatal error from
+ * the event extension.
+ */
+ private function createStreamCallback()
+ {
+ $read =& $this->readListeners;
+ $write =& $this->writeListeners;
+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
+ $key = (int) $stream;
+
+ if (\EV_READ === (\EV_READ & $flags) && isset($read[$key])) {
+ \call_user_func($read[$key], $stream);
+ }
+
+ if (\EV_WRITE === (\EV_WRITE & $flags) && isset($write[$key])) {
+ \call_user_func($write[$key], $stream);
+ }
+ };
+ }
+}
diff --git a/vendor/react/event-loop/src/ExtUvLoop.php b/vendor/react/event-loop/src/ExtUvLoop.php
new file mode 100644
index 0000000..631a459
--- /dev/null
+++ b/vendor/react/event-loop/src/ExtUvLoop.php
@@ -0,0 +1,342 @@
+<?php
+
+namespace React\EventLoop;
+
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use SplObjectStorage;
+
+/**
+ * An `ext-uv` based event loop.
+ *
+ * This loop uses the [`uv` PECL extension](https://pecl.php.net/package/uv),
+ * that provides an interface to `libuv` library.
+ * `libuv` itself supports a number of system-specific backends (epoll, kqueue).
+ *
+ * This loop is known to work with PHP 7.x.
+ *
+ * @see https://github.com/bwoebi/php-uv
+ */
+final class ExtUvLoop implements LoopInterface
+{
+ private $uv;
+ private $futureTickQueue;
+ private $timers;
+ private $streamEvents = array();
+ private $readStreams = array();
+ private $writeStreams = array();
+ private $running;
+ private $signals;
+ private $signalEvents = array();
+ private $streamListener;
+
+ public function __construct()
+ {
+ if (!\function_exists('uv_loop_new')) {
+ throw new \BadMethodCallException('Cannot create LibUvLoop, ext-uv extension missing');
+ }
+
+ $this->uv = \uv_loop_new();
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timers = new SplObjectStorage();
+ $this->streamListener = $this->createStreamListener();
+ $this->signals = new SignalsHandler();
+ }
+
+ /**
+ * Returns the underlying ext-uv event loop. (Internal ReactPHP use only.)
+ *
+ * @internal
+ *
+ * @return resource
+ */
+ public function getUvLoop()
+ {
+ return $this->uv;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addReadStream($stream, $listener)
+ {
+ if (isset($this->readStreams[(int) $stream])) {
+ return;
+ }
+
+ $this->readStreams[(int) $stream] = $listener;
+ $this->addStream($stream);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addWriteStream($stream, $listener)
+ {
+ if (isset($this->writeStreams[(int) $stream])) {
+ return;
+ }
+
+ $this->writeStreams[(int) $stream] = $listener;
+ $this->addStream($stream);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeReadStream($stream)
+ {
+ if (!isset($this->streamEvents[(int) $stream])) {
+ return;
+ }
+
+ unset($this->readStreams[(int) $stream]);
+ $this->removeStream($stream);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeWriteStream($stream)
+ {
+ if (!isset($this->streamEvents[(int) $stream])) {
+ return;
+ }
+
+ unset($this->writeStreams[(int) $stream]);
+ $this->removeStream($stream);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $that = $this;
+ $timers = $this->timers;
+ $callback = function () use ($timer, $timers, $that) {
+ \call_user_func($timer->getCallback(), $timer);
+
+ if ($timers->contains($timer)) {
+ $that->cancelTimer($timer);
+ }
+ };
+
+ $event = \uv_timer_init($this->uv);
+ $this->timers->attach($timer, $event);
+ \uv_timer_start(
+ $event,
+ $this->convertFloatSecondsToMilliseconds($interval),
+ 0,
+ $callback
+ );
+
+ return $timer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $callback = function () use ($timer) {
+ \call_user_func($timer->getCallback(), $timer);
+ };
+
+ $interval = $this->convertFloatSecondsToMilliseconds($interval);
+ $event = \uv_timer_init($this->uv);
+ $this->timers->attach($timer, $event);
+ \uv_timer_start(
+ $event,
+ $interval,
+ (int) $interval === 0 ? 1 : $interval,
+ $callback
+ );
+
+ return $timer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function cancelTimer(TimerInterface $timer)
+ {
+ if (isset($this->timers[$timer])) {
+ @\uv_timer_stop($this->timers[$timer]);
+ $this->timers->detach($timer);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ $this->signals->add($signal, $listener);
+
+ if (!isset($this->signalEvents[$signal])) {
+ $signals = $this->signals;
+ $this->signalEvents[$signal] = \uv_signal_init($this->uv);
+ \uv_signal_start($this->signalEvents[$signal], function () use ($signals, $signal) {
+ $signals->call($signal);
+ }, $signal);
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ $this->signals->remove($signal, $listener);
+
+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
+ \uv_signal_stop($this->signalEvents[$signal]);
+ unset($this->signalEvents[$signal]);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
+ $wasJustStopped = !$this->running;
+ $nothingLeftToDo = !$this->readStreams
+ && !$this->writeStreams
+ && !$this->timers->count()
+ && $this->signals->isEmpty();
+
+ // Use UV::RUN_ONCE when there are only I/O events active in the loop and block until one of those triggers,
+ // otherwise use UV::RUN_NOWAIT.
+ // @link http://docs.libuv.org/en/v1.x/loop.html#c.uv_run
+ $flags = \UV::RUN_ONCE;
+ if ($wasJustStopped || $hasPendingCallbacks) {
+ $flags = \UV::RUN_NOWAIT;
+ } elseif ($nothingLeftToDo) {
+ break;
+ }
+
+ \uv_run($this->uv, $flags);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ private function addStream($stream)
+ {
+ if (!isset($this->streamEvents[(int) $stream])) {
+ $this->streamEvents[(int)$stream] = \uv_poll_init_socket($this->uv, $stream);
+ }
+
+ if ($this->streamEvents[(int) $stream] !== false) {
+ $this->pollStream($stream);
+ }
+ }
+
+ private function removeStream($stream)
+ {
+ if (!isset($this->streamEvents[(int) $stream])) {
+ return;
+ }
+
+ if (!isset($this->readStreams[(int) $stream])
+ && !isset($this->writeStreams[(int) $stream])) {
+ \uv_poll_stop($this->streamEvents[(int) $stream]);
+ \uv_close($this->streamEvents[(int) $stream]);
+ unset($this->streamEvents[(int) $stream]);
+ return;
+ }
+
+ $this->pollStream($stream);
+ }
+
+ private function pollStream($stream)
+ {
+ if (!isset($this->streamEvents[(int) $stream])) {
+ return;
+ }
+
+ $flags = 0;
+ if (isset($this->readStreams[(int) $stream])) {
+ $flags |= \UV::READABLE;
+ }
+
+ if (isset($this->writeStreams[(int) $stream])) {
+ $flags |= \UV::WRITABLE;
+ }
+
+ \uv_poll_start($this->streamEvents[(int) $stream], $flags, $this->streamListener);
+ }
+
+ /**
+ * Create a stream listener
+ *
+ * @return callable Returns a callback
+ */
+ private function createStreamListener()
+ {
+ $callback = function ($event, $status, $events, $stream) {
+ // libuv automatically stops polling on error, re-enable polling to match other loop implementations
+ if ($status !== 0) {
+ $this->pollStream($stream);
+
+ // libuv may report no events on error, but this should still invoke stream listeners to report closed connections
+ // re-enable both readable and writable, correct listeners will be checked below anyway
+ if ($events === 0) {
+ $events = \UV::READABLE | \UV::WRITABLE;
+ }
+ }
+
+ if (isset($this->readStreams[(int) $stream]) && ($events & \UV::READABLE)) {
+ \call_user_func($this->readStreams[(int) $stream], $stream);
+ }
+
+ if (isset($this->writeStreams[(int) $stream]) && ($events & \UV::WRITABLE)) {
+ \call_user_func($this->writeStreams[(int) $stream], $stream);
+ }
+ };
+
+ return $callback;
+ }
+
+ /**
+ * @param float $interval
+ * @return int
+ */
+ private function convertFloatSecondsToMilliseconds($interval)
+ {
+ if ($interval < 0) {
+ return 0;
+ }
+
+ $maxValue = (int) (\PHP_INT_MAX / 1000);
+ $intInterval = (int) $interval;
+
+ if (($intInterval <= 0 && $interval > 1) || $intInterval >= $maxValue) {
+ throw new \InvalidArgumentException(
+ "Interval overflow, value must be lower than '{$maxValue}', but '{$interval}' passed."
+ );
+ }
+
+ return (int) \floor($interval * 1000);
+ }
+}
diff --git a/vendor/react/event-loop/src/Factory.php b/vendor/react/event-loop/src/Factory.php
new file mode 100644
index 0000000..30bbfd7
--- /dev/null
+++ b/vendor/react/event-loop/src/Factory.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace React\EventLoop;
+
+/**
+ * [Deprecated] The `Factory` class exists as a convenient way to pick the best available event loop implementation.
+ *
+ * @deprecated 1.2.0 See Loop instead.
+ * @see Loop
+ */
+final class Factory
+{
+ /**
+ * [Deprecated] Creates a new event loop instance
+ *
+ * ```php
+ * // deprecated
+ * $loop = React\EventLoop\Factory::create();
+ *
+ * // new
+ * $loop = React\EventLoop\Loop::get();
+ * ```
+ *
+ * This method always returns an instance implementing `LoopInterface`,
+ * the actual event loop implementation is an implementation detail.
+ *
+ * This method should usually only be called once at the beginning of the program.
+ *
+ * @deprecated 1.2.0 See Loop::get() instead.
+ * @see Loop::get()
+ *
+ * @return LoopInterface
+ */
+ public static function create()
+ {
+ $loop = self::construct();
+
+ Loop::set($loop);
+
+ return $loop;
+ }
+
+ /**
+ * @internal
+ * @return LoopInterface
+ */
+ private static function construct()
+ {
+ // @codeCoverageIgnoreStart
+ if (\function_exists('uv_loop_new')) {
+ // only use ext-uv on PHP 7
+ return new ExtUvLoop();
+ }
+
+ if (\class_exists('libev\EventLoop', false)) {
+ return new ExtLibevLoop();
+ }
+
+ if (\class_exists('EvLoop', false)) {
+ return new ExtEvLoop();
+ }
+
+ if (\class_exists('EventBase', false)) {
+ return new ExtEventLoop();
+ }
+
+ if (\function_exists('event_base_new') && \PHP_MAJOR_VERSION === 5) {
+ // only use ext-libevent on PHP 5 for now
+ return new ExtLibeventLoop();
+ }
+
+ return new StreamSelectLoop();
+ // @codeCoverageIgnoreEnd
+ }
+}
diff --git a/vendor/react/event-loop/src/Loop.php b/vendor/react/event-loop/src/Loop.php
new file mode 100644
index 0000000..fd5d81c
--- /dev/null
+++ b/vendor/react/event-loop/src/Loop.php
@@ -0,0 +1,225 @@
+<?php
+
+namespace React\EventLoop;
+
+/**
+ * The `Loop` class exists as a convenient way to get the currently relevant loop
+ */
+final class Loop
+{
+ /**
+ * @var LoopInterface
+ */
+ private static $instance;
+
+ /** @var bool */
+ private static $stopped = false;
+
+ /**
+ * Returns the event loop.
+ * When no loop is set, it will call the factory to create one.
+ *
+ * This method always returns an instance implementing `LoopInterface`,
+ * the actual event loop implementation is an implementation detail.
+ *
+ * This method is the preferred way to get the event loop and using
+ * Factory::create has been deprecated.
+ *
+ * @return LoopInterface
+ */
+ public static function get()
+ {
+ if (self::$instance instanceof LoopInterface) {
+ return self::$instance;
+ }
+
+ self::$instance = $loop = Factory::create();
+
+ // Automatically run loop at end of program, unless already started or stopped explicitly.
+ // This is tested using child processes, so coverage is actually 100%, see BinTest.
+ // @codeCoverageIgnoreStart
+ $hasRun = false;
+ $loop->futureTick(function () use (&$hasRun) {
+ $hasRun = true;
+ });
+
+ $stopped =& self::$stopped;
+ register_shutdown_function(function () use ($loop, &$hasRun, &$stopped) {
+ // Don't run if we're coming from a fatal error (uncaught exception).
+ $error = error_get_last();
+ if ((isset($error['type']) ? $error['type'] : 0) & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
+ return;
+ }
+
+ if (!$hasRun && !$stopped) {
+ $loop->run();
+ }
+ });
+ // @codeCoverageIgnoreEnd
+
+ return self::$instance;
+ }
+
+ /**
+ * Internal undocumented method, behavior might change or throw in the
+ * future. Use with caution and at your own risk.
+ *
+ * @internal
+ * @return void
+ */
+ public static function set(LoopInterface $loop)
+ {
+ self::$instance = $loop;
+ }
+
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to read.
+ *
+ * @param resource $stream
+ * @param callable $listener
+ * @return void
+ * @throws \Exception
+ * @see LoopInterface::addReadStream()
+ */
+ public static function addReadStream($stream, $listener)
+ {
+ self::get()->addReadStream($stream, $listener);
+ }
+
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to write.
+ *
+ * @param resource $stream
+ * @param callable $listener
+ * @return void
+ * @throws \Exception
+ * @see LoopInterface::addWriteStream()
+ */
+ public static function addWriteStream($stream, $listener)
+ {
+ self::get()->addWriteStream($stream, $listener);
+ }
+
+ /**
+ * Remove the read event listener for the given stream.
+ *
+ * @param resource $stream
+ * @return void
+ * @see LoopInterface::removeReadStream()
+ */
+ public static function removeReadStream($stream)
+ {
+ self::get()->removeReadStream($stream);
+ }
+
+ /**
+ * Remove the write event listener for the given stream.
+ *
+ * @param resource $stream
+ * @return void
+ * @see LoopInterface::removeWriteStream()
+ */
+ public static function removeWriteStream($stream)
+ {
+ self::get()->removeWriteStream($stream);
+ }
+
+ /**
+ * Enqueue a callback to be invoked once after the given interval.
+ *
+ * @param float $interval
+ * @param callable $callback
+ * @return TimerInterface
+ * @see LoopInterface::addTimer()
+ */
+ public static function addTimer($interval, $callback)
+ {
+ return self::get()->addTimer($interval, $callback);
+ }
+
+ /**
+ * Enqueue a callback to be invoked repeatedly after the given interval.
+ *
+ * @param float $interval
+ * @param callable $callback
+ * @return TimerInterface
+ * @see LoopInterface::addPeriodicTimer()
+ */
+ public static function addPeriodicTimer($interval, $callback)
+ {
+ return self::get()->addPeriodicTimer($interval, $callback);
+ }
+
+ /**
+ * Cancel a pending timer.
+ *
+ * @param TimerInterface $timer
+ * @return void
+ * @see LoopInterface::cancelTimer()
+ */
+ public static function cancelTimer(TimerInterface $timer)
+ {
+ return self::get()->cancelTimer($timer);
+ }
+
+ /**
+ * Schedule a callback to be invoked on a future tick of the event loop.
+ *
+ * @param callable $listener
+ * @return void
+ * @see LoopInterface::futureTick()
+ */
+ public static function futureTick($listener)
+ {
+ self::get()->futureTick($listener);
+ }
+
+ /**
+ * Register a listener to be notified when a signal has been caught by this process.
+ *
+ * @param int $signal
+ * @param callable $listener
+ * @return void
+ * @see LoopInterface::addSignal()
+ */
+ public static function addSignal($signal, $listener)
+ {
+ self::get()->addSignal($signal, $listener);
+ }
+
+ /**
+ * Removes a previously added signal listener.
+ *
+ * @param int $signal
+ * @param callable $listener
+ * @return void
+ * @see LoopInterface::removeSignal()
+ */
+ public static function removeSignal($signal, $listener)
+ {
+ self::get()->removeSignal($signal, $listener);
+ }
+
+ /**
+ * Run the event loop until there are no more tasks to perform.
+ *
+ * @return void
+ * @see LoopInterface::run()
+ */
+ public static function run()
+ {
+ self::get()->run();
+ }
+
+ /**
+ * Instruct a running event loop to stop.
+ *
+ * @return void
+ * @see LoopInterface::stop()
+ */
+ public static function stop()
+ {
+ self::$stopped = true;
+ self::get()->stop();
+ }
+}
diff --git a/vendor/react/event-loop/src/LoopInterface.php b/vendor/react/event-loop/src/LoopInterface.php
new file mode 100644
index 0000000..9266f71
--- /dev/null
+++ b/vendor/react/event-loop/src/LoopInterface.php
@@ -0,0 +1,472 @@
+<?php
+
+namespace React\EventLoop;
+
+interface LoopInterface
+{
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to read.
+ *
+ * Note that this low-level API is considered advanced usage.
+ * Most use cases should probably use the higher-level
+ * [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
+ * instead.
+ *
+ * The first parameter MUST be a valid stream resource that supports
+ * checking whether it is ready to read by this loop implementation.
+ * A single stream resource MUST NOT be added more than once.
+ * Instead, either call [`removeReadStream()`](#removereadstream) first or
+ * react to this event with a single listener and then dispatch from this
+ * listener. This method MAY throw an `Exception` if the given resource type
+ * is not supported by this loop implementation.
+ *
+ * The second parameter MUST be a listener callback function that accepts
+ * the stream resource as its only parameter.
+ * If you don't use the stream resource inside your listener callback function
+ * you MAY use a function which has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * $loop->addReadStream($stream, function ($stream) use ($name) {
+ * echo $name . ' said: ' . fread($stream);
+ * });
+ * ```
+ *
+ * See also [example #11](examples).
+ *
+ * You can invoke [`removeReadStream()`](#removereadstream) to remove the
+ * read event listener for this stream.
+ *
+ * The execution order of listeners when multiple streams become ready at
+ * the same time is not guaranteed.
+ *
+ * @param resource $stream The PHP stream resource to check.
+ * @param callable $listener Invoked when the stream is ready.
+ * @throws \Exception if the given resource type is not supported by this loop implementation
+ * @see self::removeReadStream()
+ */
+ public function addReadStream($stream, $listener);
+
+ /**
+ * [Advanced] Register a listener to be notified when a stream is ready to write.
+ *
+ * Note that this low-level API is considered advanced usage.
+ * Most use cases should probably use the higher-level
+ * [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
+ * instead.
+ *
+ * The first parameter MUST be a valid stream resource that supports
+ * checking whether it is ready to write by this loop implementation.
+ * A single stream resource MUST NOT be added more than once.
+ * Instead, either call [`removeWriteStream()`](#removewritestream) first or
+ * react to this event with a single listener and then dispatch from this
+ * listener. This method MAY throw an `Exception` if the given resource type
+ * is not supported by this loop implementation.
+ *
+ * The second parameter MUST be a listener callback function that accepts
+ * the stream resource as its only parameter.
+ * If you don't use the stream resource inside your listener callback function
+ * you MAY use a function which has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * $loop->addWriteStream($stream, function ($stream) use ($name) {
+ * fwrite($stream, 'Hello ' . $name);
+ * });
+ * ```
+ *
+ * See also [example #12](examples).
+ *
+ * You can invoke [`removeWriteStream()`](#removewritestream) to remove the
+ * write event listener for this stream.
+ *
+ * The execution order of listeners when multiple streams become ready at
+ * the same time is not guaranteed.
+ *
+ * Some event loop implementations are known to only trigger the listener if
+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
+ * stream has already been readable from the beginning.
+ * This also implies that a stream may not be recognized as readable when data
+ * is still left in PHP's internal stream buffers.
+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
+ * to disable PHP's internal read buffer in this case.
+ *
+ * @param resource $stream The PHP stream resource to check.
+ * @param callable $listener Invoked when the stream is ready.
+ * @throws \Exception if the given resource type is not supported by this loop implementation
+ * @see self::removeWriteStream()
+ */
+ public function addWriteStream($stream, $listener);
+
+ /**
+ * Remove the read event listener for the given stream.
+ *
+ * Removing a stream from the loop that has already been removed or trying
+ * to remove a stream that was never added or is invalid has no effect.
+ *
+ * @param resource $stream The PHP stream resource.
+ */
+ public function removeReadStream($stream);
+
+ /**
+ * Remove the write event listener for the given stream.
+ *
+ * Removing a stream from the loop that has already been removed or trying
+ * to remove a stream that was never added or is invalid has no effect.
+ *
+ * @param resource $stream The PHP stream resource.
+ */
+ public function removeWriteStream($stream);
+
+ /**
+ * Enqueue a callback to be invoked once after the given interval.
+ *
+ * The second parameter MUST be a timer callback function that accepts
+ * the timer instance as its only parameter.
+ * If you don't use the timer instance inside your timer callback function
+ * you MAY use a function which has no parameters at all.
+ *
+ * The timer callback function MUST NOT throw an `Exception`.
+ * The return value of the timer callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * This method returns a timer instance. The same timer instance will also be
+ * passed into the timer callback function as described above.
+ * You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
+ * Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
+ * the callback will be invoked only once after the given interval.
+ *
+ * ```php
+ * $loop->addTimer(0.8, function () {
+ * echo 'world!' . PHP_EOL;
+ * });
+ *
+ * $loop->addTimer(0.3, function () {
+ * echo 'hello ';
+ * });
+ * ```
+ *
+ * See also [example #1](examples).
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $loop->addTimer(1.0, function () use ($name) {
+ * echo "hello $name\n";
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * This interface does not enforce any particular timer resolution, so
+ * special care may have to be taken if you rely on very high precision with
+ * millisecond accuracy or below. Event loop implementations SHOULD work on
+ * a best effort basis and SHOULD provide at least millisecond accuracy
+ * unless otherwise noted. Many existing event loop implementations are
+ * known to provide microsecond accuracy, but it's generally not recommended
+ * to rely on this high precision.
+ *
+ * Similarly, the execution order of timers scheduled to execute at the
+ * same time (within its possible accuracy) is not guaranteed.
+ *
+ * This interface suggests that event loop implementations SHOULD use a
+ * monotonic time source if available. Given that a monotonic time source is
+ * only available as of PHP 7.3 by default, event loop implementations MAY
+ * fall back to using wall-clock time.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s and then adjust
+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
+ * See also [event loop implementations](#loop-implementations) for more details.
+ *
+ * @param int|float $interval The number of seconds to wait before execution.
+ * @param callable $callback The callback to invoke.
+ *
+ * @return TimerInterface
+ */
+ public function addTimer($interval, $callback);
+
+ /**
+ * Enqueue a callback to be invoked repeatedly after the given interval.
+ *
+ * The second parameter MUST be a timer callback function that accepts
+ * the timer instance as its only parameter.
+ * If you don't use the timer instance inside your timer callback function
+ * you MAY use a function which has no parameters at all.
+ *
+ * The timer callback function MUST NOT throw an `Exception`.
+ * The return value of the timer callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * This method returns a timer instance. The same timer instance will also be
+ * passed into the timer callback function as described above.
+ * Unlike [`addTimer()`](#addtimer), this method will ensure the callback
+ * will be invoked infinitely after the given interval or until you invoke
+ * [`cancelTimer`](#canceltimer).
+ *
+ * ```php
+ * $timer = $loop->addPeriodicTimer(0.1, function () {
+ * echo 'tick!' . PHP_EOL;
+ * });
+ *
+ * $loop->addTimer(1.0, function () use ($loop, $timer) {
+ * $loop->cancelTimer($timer);
+ * echo 'Done' . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [example #2](examples).
+ *
+ * If you want to limit the number of executions, you can bind
+ * arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $n = 3;
+ * $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
+ * if ($n > 0) {
+ * --$n;
+ * echo "hello $name\n";
+ * } else {
+ * $loop->cancelTimer($timer);
+ * }
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * This interface does not enforce any particular timer resolution, so
+ * special care may have to be taken if you rely on very high precision with
+ * millisecond accuracy or below. Event loop implementations SHOULD work on
+ * a best effort basis and SHOULD provide at least millisecond accuracy
+ * unless otherwise noted. Many existing event loop implementations are
+ * known to provide microsecond accuracy, but it's generally not recommended
+ * to rely on this high precision.
+ *
+ * Similarly, the execution order of timers scheduled to execute at the
+ * same time (within its possible accuracy) is not guaranteed.
+ *
+ * This interface suggests that event loop implementations SHOULD use a
+ * monotonic time source if available. Given that a monotonic time source is
+ * only available as of PHP 7.3 by default, event loop implementations MAY
+ * fall back to using wall-clock time.
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s and then adjust
+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
+ * See also [event loop implementations](#loop-implementations) for more details.
+ *
+ * Additionally, periodic timers may be subject to timer drift due to
+ * re-scheduling after each invocation. As such, it's generally not
+ * recommended to rely on this for high precision intervals with millisecond
+ * accuracy or below.
+ *
+ * @param int|float $interval The number of seconds to wait before execution.
+ * @param callable $callback The callback to invoke.
+ *
+ * @return TimerInterface
+ */
+ public function addPeriodicTimer($interval, $callback);
+
+ /**
+ * Cancel a pending timer.
+ *
+ * See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
+ *
+ * Calling this method on a timer instance that has not been added to this
+ * loop instance or on a timer that has already been cancelled has no effect.
+ *
+ * @param TimerInterface $timer The timer to cancel.
+ *
+ * @return void
+ */
+ public function cancelTimer(TimerInterface $timer);
+
+ /**
+ * Schedule a callback to be invoked on a future tick of the event loop.
+ *
+ * This works very much similar to timers with an interval of zero seconds,
+ * but does not require the overhead of scheduling a timer queue.
+ *
+ * The tick callback function MUST be able to accept zero parameters.
+ *
+ * The tick callback function MUST NOT throw an `Exception`.
+ * The return value of the tick callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * If you want to access any variables within your callback function, you
+ * can bind arbitrary data to a callback closure like this:
+ *
+ * ```php
+ * function hello($name, LoopInterface $loop)
+ * {
+ * $loop->futureTick(function () use ($name) {
+ * echo "hello $name\n";
+ * });
+ * }
+ *
+ * hello('Tester', $loop);
+ * ```
+ *
+ * Unlike timers, tick callbacks are guaranteed to be executed in the order
+ * they are enqueued.
+ * Also, once a callback is enqueued, there's no way to cancel this operation.
+ *
+ * This is often used to break down bigger tasks into smaller steps (a form
+ * of cooperative multitasking).
+ *
+ * ```php
+ * $loop->futureTick(function () {
+ * echo 'b';
+ * });
+ * $loop->futureTick(function () {
+ * echo 'c';
+ * });
+ * echo 'a';
+ * ```
+ *
+ * See also [example #3](examples).
+ *
+ * @param callable $listener The callback to invoke.
+ *
+ * @return void
+ */
+ public function futureTick($listener);
+
+ /**
+ * Register a listener to be notified when a signal has been caught by this process.
+ *
+ * This is useful to catch user interrupt signals or shutdown signals from
+ * tools like `supervisor` or `systemd`.
+ *
+ * The second parameter MUST be a listener callback function that accepts
+ * the signal as its only parameter.
+ * If you don't use the signal inside your listener callback function
+ * you MAY use a function which has no parameters at all.
+ *
+ * The listener callback function MUST NOT throw an `Exception`.
+ * The return value of the listener callback function will be ignored and has
+ * no effect, so for performance reasons you're recommended to not return
+ * any excessive data structures.
+ *
+ * ```php
+ * $loop->addSignal(SIGINT, function (int $signal) {
+ * echo 'Caught user interrupt signal' . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [example #4](examples).
+ *
+ * Signaling is only available on Unix-like platforms, Windows isn't
+ * supported due to operating system limitations.
+ * This method may throw a `BadMethodCallException` if signals aren't
+ * supported on this platform, for example when required extensions are
+ * missing.
+ *
+ * **Note: A listener can only be added once to the same signal, any
+ * attempts to add it more than once will be ignored.**
+ *
+ * @param int $signal
+ * @param callable $listener
+ *
+ * @throws \BadMethodCallException when signals aren't supported on this
+ * platform, for example when required extensions are missing.
+ *
+ * @return void
+ */
+ public function addSignal($signal, $listener);
+
+ /**
+ * Removes a previously added signal listener.
+ *
+ * ```php
+ * $loop->removeSignal(SIGINT, $listener);
+ * ```
+ *
+ * Any attempts to remove listeners that aren't registered will be ignored.
+ *
+ * @param int $signal
+ * @param callable $listener
+ *
+ * @return void
+ */
+ public function removeSignal($signal, $listener);
+
+ /**
+ * Run the event loop until there are no more tasks to perform.
+ *
+ * For many applications, this method is the only directly visible
+ * invocation on the event loop.
+ * As a rule of thumb, it is usually recommended to attach everything to the
+ * same loop instance and then run the loop once at the bottom end of the
+ * application.
+ *
+ * ```php
+ * $loop->run();
+ * ```
+ *
+ * This method will keep the loop running until there are no more tasks
+ * to perform. In other words: This method will block until the last
+ * timer, stream and/or signal has been removed.
+ *
+ * Likewise, it is imperative to ensure the application actually invokes
+ * this method once. Adding listeners to the loop and missing to actually
+ * run it will result in the application exiting without actually waiting
+ * for any of the attached listeners.
+ *
+ * This method MUST NOT be called while the loop is already running.
+ * This method MAY be called more than once after it has explicitly been
+ * [`stop()`ped](#stop) or after it automatically stopped because it
+ * previously did no longer have anything to do.
+ *
+ * @return void
+ */
+ public function run();
+
+ /**
+ * Instruct a running event loop to stop.
+ *
+ * This method is considered advanced usage and should be used with care.
+ * As a rule of thumb, it is usually recommended to let the loop stop
+ * only automatically when it no longer has anything to do.
+ *
+ * This method can be used to explicitly instruct the event loop to stop:
+ *
+ * ```php
+ * $loop->addTimer(3.0, function () use ($loop) {
+ * $loop->stop();
+ * });
+ * ```
+ *
+ * Calling this method on a loop instance that is not currently running or
+ * on a loop instance that has already been stopped has no effect.
+ *
+ * @return void
+ */
+ public function stop();
+}
diff --git a/vendor/react/event-loop/src/SignalsHandler.php b/vendor/react/event-loop/src/SignalsHandler.php
new file mode 100644
index 0000000..10d125d
--- /dev/null
+++ b/vendor/react/event-loop/src/SignalsHandler.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace React\EventLoop;
+
+/**
+ * @internal
+ */
+final class SignalsHandler
+{
+ private $signals = array();
+
+ public function add($signal, $listener)
+ {
+ if (!isset($this->signals[$signal])) {
+ $this->signals[$signal] = array();
+ }
+
+ if (\in_array($listener, $this->signals[$signal])) {
+ return;
+ }
+
+ $this->signals[$signal][] = $listener;
+ }
+
+ public function remove($signal, $listener)
+ {
+ if (!isset($this->signals[$signal])) {
+ return;
+ }
+
+ $index = \array_search($listener, $this->signals[$signal], true);
+ unset($this->signals[$signal][$index]);
+
+ if (isset($this->signals[$signal]) && \count($this->signals[$signal]) === 0) {
+ unset($this->signals[$signal]);
+ }
+ }
+
+ public function call($signal)
+ {
+ if (!isset($this->signals[$signal])) {
+ return;
+ }
+
+ foreach ($this->signals[$signal] as $listener) {
+ \call_user_func($listener, $signal);
+ }
+ }
+
+ public function count($signal)
+ {
+ if (!isset($this->signals[$signal])) {
+ return 0;
+ }
+
+ return \count($this->signals[$signal]);
+ }
+
+ public function isEmpty()
+ {
+ return !$this->signals;
+ }
+}
diff --git a/vendor/react/event-loop/src/StreamSelectLoop.php b/vendor/react/event-loop/src/StreamSelectLoop.php
new file mode 100644
index 0000000..71983da
--- /dev/null
+++ b/vendor/react/event-loop/src/StreamSelectLoop.php
@@ -0,0 +1,329 @@
+<?php
+
+namespace React\EventLoop;
+
+use React\EventLoop\Tick\FutureTickQueue;
+use React\EventLoop\Timer\Timer;
+use React\EventLoop\Timer\Timers;
+
+/**
+ * A `stream_select()` based event loop.
+ *
+ * This uses the [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
+ * function and is the only implementation that works out of the box with PHP.
+ *
+ * This event loop works out of the box on PHP 5.4 through PHP 8+ and HHVM.
+ * This means that no installation is required and this library works on all
+ * platforms and supported PHP versions.
+ * Accordingly, the [`Loop` class](#loop) and the deprecated [`Factory`](#factory)
+ * will use this event loop by default if you do not install any of the event loop
+ * extensions listed below.
+ *
+ * Under the hood, it does a simple `select` system call.
+ * This system call is limited to the maximum file descriptor number of
+ * `FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`
+ * (`m` being the maximum file descriptor number passed).
+ * This means that you may run into issues when handling thousands of streams
+ * concurrently and you may want to look into using one of the alternative
+ * event loop implementations listed below in this case.
+ * If your use case is among the many common use cases that involve handling only
+ * dozens or a few hundred streams at once, then this event loop implementation
+ * performs really well.
+ *
+ * If you want to use signal handling (see also [`addSignal()`](#addsignal) below),
+ * this event loop implementation requires `ext-pcntl`.
+ * This extension is only available for Unix-like platforms and does not support
+ * Windows.
+ * It is commonly installed as part of many PHP distributions.
+ * If this extension is missing (or you're running on Windows), signal handling is
+ * not supported and throws a `BadMethodCallException` instead.
+ *
+ * This event loop is known to rely on wall-clock time to schedule future timers
+ * when using any version before PHP 7.3, because a monotonic time source is
+ * only available as of PHP 7.3 (`hrtime()`).
+ * While this does not affect many common use cases, this is an important
+ * distinction for programs that rely on a high time precision or on systems
+ * that are subject to discontinuous time adjustments (time jumps).
+ * This means that if you schedule a timer to trigger in 30s on PHP < 7.3 and
+ * then adjust your system time forward by 20s, the timer may trigger in 10s.
+ * See also [`addTimer()`](#addtimer) for more details.
+ *
+ * @link https://www.php.net/manual/en/function.stream-select.php
+ */
+final class StreamSelectLoop implements LoopInterface
+{
+ /** @internal */
+ const MICROSECONDS_PER_SECOND = 1000000;
+
+ private $futureTickQueue;
+ private $timers;
+ private $readStreams = array();
+ private $readListeners = array();
+ private $writeStreams = array();
+ private $writeListeners = array();
+ private $running;
+ private $pcntl = false;
+ private $pcntlPoll = false;
+ private $signals;
+
+ public function __construct()
+ {
+ $this->futureTickQueue = new FutureTickQueue();
+ $this->timers = new Timers();
+ $this->pcntl = \function_exists('pcntl_signal') && \function_exists('pcntl_signal_dispatch');
+ $this->pcntlPoll = $this->pcntl && !\function_exists('pcntl_async_signals');
+ $this->signals = new SignalsHandler();
+
+ // prefer async signals if available (PHP 7.1+) or fall back to dispatching on each tick
+ if ($this->pcntl && !$this->pcntlPoll) {
+ \pcntl_async_signals(true);
+ }
+ }
+
+ public function addReadStream($stream, $listener)
+ {
+ $key = (int) $stream;
+
+ if (!isset($this->readStreams[$key])) {
+ $this->readStreams[$key] = $stream;
+ $this->readListeners[$key] = $listener;
+ }
+ }
+
+ public function addWriteStream($stream, $listener)
+ {
+ $key = (int) $stream;
+
+ if (!isset($this->writeStreams[$key])) {
+ $this->writeStreams[$key] = $stream;
+ $this->writeListeners[$key] = $listener;
+ }
+ }
+
+ public function removeReadStream($stream)
+ {
+ $key = (int) $stream;
+
+ unset(
+ $this->readStreams[$key],
+ $this->readListeners[$key]
+ );
+ }
+
+ public function removeWriteStream($stream)
+ {
+ $key = (int) $stream;
+
+ unset(
+ $this->writeStreams[$key],
+ $this->writeListeners[$key]
+ );
+ }
+
+ public function addTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, false);
+
+ $this->timers->add($timer);
+
+ return $timer;
+ }
+
+ public function addPeriodicTimer($interval, $callback)
+ {
+ $timer = new Timer($interval, $callback, true);
+
+ $this->timers->add($timer);
+
+ return $timer;
+ }
+
+ public function cancelTimer(TimerInterface $timer)
+ {
+ $this->timers->cancel($timer);
+ }
+
+ public function futureTick($listener)
+ {
+ $this->futureTickQueue->add($listener);
+ }
+
+ public function addSignal($signal, $listener)
+ {
+ if ($this->pcntl === false) {
+ throw new \BadMethodCallException('Event loop feature "signals" isn\'t supported by the "StreamSelectLoop"');
+ }
+
+ $first = $this->signals->count($signal) === 0;
+ $this->signals->add($signal, $listener);
+
+ if ($first) {
+ \pcntl_signal($signal, array($this->signals, 'call'));
+ }
+ }
+
+ public function removeSignal($signal, $listener)
+ {
+ if (!$this->signals->count($signal)) {
+ return;
+ }
+
+ $this->signals->remove($signal, $listener);
+
+ if ($this->signals->count($signal) === 0) {
+ \pcntl_signal($signal, \SIG_DFL);
+ }
+ }
+
+ public function run()
+ {
+ $this->running = true;
+
+ while ($this->running) {
+ $this->futureTickQueue->tick();
+
+ $this->timers->tick();
+
+ // Future-tick queue has pending callbacks ...
+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
+ $timeout = 0;
+
+ // There is a pending timer, only block until it is due ...
+ } elseif ($scheduledAt = $this->timers->getFirst()) {
+ $timeout = $scheduledAt - $this->timers->getTime();
+ if ($timeout < 0) {
+ $timeout = 0;
+ } else {
+ // Convert float seconds to int microseconds.
+ // Ensure we do not exceed maximum integer size, which may
+ // cause the loop to tick once every ~35min on 32bit systems.
+ $timeout *= self::MICROSECONDS_PER_SECOND;
+ $timeout = $timeout > \PHP_INT_MAX ? \PHP_INT_MAX : (int)$timeout;
+ }
+
+ // The only possible event is stream or signal activity, so wait forever ...
+ } elseif ($this->readStreams || $this->writeStreams || !$this->signals->isEmpty()) {
+ $timeout = null;
+
+ // There's nothing left to do ...
+ } else {
+ break;
+ }
+
+ $this->waitForStreamActivity($timeout);
+ }
+ }
+
+ public function stop()
+ {
+ $this->running = false;
+ }
+
+ /**
+ * Wait/check for stream activity, or until the next timer is due.
+ *
+ * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
+ */
+ private function waitForStreamActivity($timeout)
+ {
+ $read = $this->readStreams;
+ $write = $this->writeStreams;
+
+ $available = $this->streamSelect($read, $write, $timeout);
+ if ($this->pcntlPoll) {
+ \pcntl_signal_dispatch();
+ }
+ if (false === $available) {
+ // if a system call has been interrupted,
+ // we cannot rely on it's outcome
+ return;
+ }
+
+ foreach ($read as $stream) {
+ $key = (int) $stream;
+
+ if (isset($this->readListeners[$key])) {
+ \call_user_func($this->readListeners[$key], $stream);
+ }
+ }
+
+ foreach ($write as $stream) {
+ $key = (int) $stream;
+
+ if (isset($this->writeListeners[$key])) {
+ \call_user_func($this->writeListeners[$key], $stream);
+ }
+ }
+ }
+
+ /**
+ * Emulate a stream_select() implementation that does not break when passed
+ * empty stream arrays.
+ *
+ * @param array $read An array of read streams to select upon.
+ * @param array $write An array of write streams to select upon.
+ * @param int|null $timeout Activity timeout in microseconds, or null to wait forever.
+ *
+ * @return int|false The total number of streams that are ready for read/write.
+ * Can return false if stream_select() is interrupted by a signal.
+ */
+ private function streamSelect(array &$read, array &$write, $timeout)
+ {
+ if ($read || $write) {
+ // We do not usually use or expose the `exceptfds` parameter passed to the underlying `select`.
+ // However, Windows does not report failed connection attempts in `writefds` passed to `select` like most other platforms.
+ // Instead, it uses `writefds` only for successful connection attempts and `exceptfds` for failed connection attempts.
+ // We work around this by adding all sockets that look like a pending connection attempt to `exceptfds` automatically on Windows and merge it back later.
+ // This ensures the public API matches other loop implementations across all platforms (see also test suite or rather test matrix).
+ // Lacking better APIs, every write-only socket that has not yet read any data is assumed to be in a pending connection attempt state.
+ // @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select
+ $except = null;
+ if (\DIRECTORY_SEPARATOR === '\\') {
+ $except = array();
+ foreach ($write as $key => $socket) {
+ if (!isset($read[$key]) && @\ftell($socket) === 0) {
+ $except[$key] = $socket;
+ }
+ }
+ }
+
+ /** @var ?callable $previous */
+ $previous = \set_error_handler(function ($errno, $errstr) use (&$previous) {
+ // suppress warnings that occur when `stream_select()` is interrupted by a signal
+ $eintr = \defined('SOCKET_EINTR') ? \SOCKET_EINTR : 4;
+ if ($errno === \E_WARNING && \strpos($errstr, '[' . $eintr .']: ') !== false) {
+ return;
+ }
+
+ // forward any other error to registered error handler or print warning
+ return ($previous !== null) ? \call_user_func_array($previous, \func_get_args()) : false;
+ });
+
+ try {
+ $ret = \stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout);
+ \restore_error_handler();
+ } catch (\Throwable $e) { // @codeCoverageIgnoreStart
+ \restore_error_handler();
+ throw $e;
+ } catch (\Exception $e) {
+ \restore_error_handler();
+ throw $e;
+ } // @codeCoverageIgnoreEnd
+
+ if ($except) {
+ $write = \array_merge($write, $except);
+ }
+ return $ret;
+ }
+
+ if ($timeout > 0) {
+ \usleep($timeout);
+ } elseif ($timeout === null) {
+ // wait forever (we only reach this if we're only awaiting signals)
+ // this may be interrupted and return earlier when a signal is received
+ \sleep(PHP_INT_MAX);
+ }
+
+ return 0;
+ }
+}
diff --git a/vendor/react/event-loop/src/Tick/FutureTickQueue.php b/vendor/react/event-loop/src/Tick/FutureTickQueue.php
new file mode 100644
index 0000000..efabcbc
--- /dev/null
+++ b/vendor/react/event-loop/src/Tick/FutureTickQueue.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace React\EventLoop\Tick;
+
+use SplQueue;
+
+/**
+ * A tick queue implementation that can hold multiple callback functions
+ *
+ * This class should only be used internally, see LoopInterface instead.
+ *
+ * @see LoopInterface
+ * @internal
+ */
+final class FutureTickQueue
+{
+ private $queue;
+
+ public function __construct()
+ {
+ $this->queue = new SplQueue();
+ }
+
+ /**
+ * Add a callback to be invoked on a future tick of the event loop.
+ *
+ * Callbacks are guaranteed to be executed in the order they are enqueued.
+ *
+ * @param callable $listener The callback to invoke.
+ */
+ public function add($listener)
+ {
+ $this->queue->enqueue($listener);
+ }
+
+ /**
+ * Flush the callback queue.
+ */
+ public function tick()
+ {
+ // Only invoke as many callbacks as were on the queue when tick() was called.
+ $count = $this->queue->count();
+
+ while ($count--) {
+ \call_user_func(
+ $this->queue->dequeue()
+ );
+ }
+ }
+
+ /**
+ * Check if the next tick queue is empty.
+ *
+ * @return boolean
+ */
+ public function isEmpty()
+ {
+ return $this->queue->isEmpty();
+ }
+}
diff --git a/vendor/react/event-loop/src/Timer/Timer.php b/vendor/react/event-loop/src/Timer/Timer.php
new file mode 100644
index 0000000..da3602a
--- /dev/null
+++ b/vendor/react/event-loop/src/Timer/Timer.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace React\EventLoop\Timer;
+
+use React\EventLoop\TimerInterface;
+
+/**
+ * The actual connection implementation for TimerInterface
+ *
+ * This class should only be used internally, see TimerInterface instead.
+ *
+ * @see TimerInterface
+ * @internal
+ */
+final class Timer implements TimerInterface
+{
+ const MIN_INTERVAL = 0.000001;
+
+ private $interval;
+ private $callback;
+ private $periodic;
+
+ /**
+ * Constructor initializes the fields of the Timer
+ *
+ * @param float $interval The interval after which this timer will execute, in seconds
+ * @param callable $callback The callback that will be executed when this timer elapses
+ * @param bool $periodic Whether the time is periodic
+ */
+ public function __construct($interval, $callback, $periodic = false)
+ {
+ if ($interval < self::MIN_INTERVAL) {
+ $interval = self::MIN_INTERVAL;
+ }
+
+ $this->interval = (float) $interval;
+ $this->callback = $callback;
+ $this->periodic = (bool) $periodic;
+ }
+
+ public function getInterval()
+ {
+ return $this->interval;
+ }
+
+ public function getCallback()
+ {
+ return $this->callback;
+ }
+
+ public function isPeriodic()
+ {
+ return $this->periodic;
+ }
+}
diff --git a/vendor/react/event-loop/src/Timer/Timers.php b/vendor/react/event-loop/src/Timer/Timers.php
new file mode 100644
index 0000000..3a33b8c
--- /dev/null
+++ b/vendor/react/event-loop/src/Timer/Timers.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace React\EventLoop\Timer;
+
+use React\EventLoop\TimerInterface;
+
+/**
+ * A scheduler implementation that can hold multiple timer instances
+ *
+ * This class should only be used internally, see TimerInterface instead.
+ *
+ * @see TimerInterface
+ * @internal
+ */
+final class Timers
+{
+ private $time;
+ private $timers = array();
+ private $schedule = array();
+ private $sorted = true;
+ private $useHighResolution;
+
+ public function __construct()
+ {
+ // prefer high-resolution timer, available as of PHP 7.3+
+ $this->useHighResolution = \function_exists('hrtime');
+ }
+
+ public function updateTime()
+ {
+ return $this->time = $this->useHighResolution ? \hrtime(true) * 1e-9 : \microtime(true);
+ }
+
+ public function getTime()
+ {
+ return $this->time ?: $this->updateTime();
+ }
+
+ public function add(TimerInterface $timer)
+ {
+ $id = \spl_object_hash($timer);
+ $this->timers[$id] = $timer;
+ $this->schedule[$id] = $timer->getInterval() + $this->updateTime();
+ $this->sorted = false;
+ }
+
+ public function contains(TimerInterface $timer)
+ {
+ return isset($this->timers[\spl_object_hash($timer)]);
+ }
+
+ public function cancel(TimerInterface $timer)
+ {
+ $id = \spl_object_hash($timer);
+ unset($this->timers[$id], $this->schedule[$id]);
+ }
+
+ public function getFirst()
+ {
+ // ensure timers are sorted to simply accessing next (first) one
+ if (!$this->sorted) {
+ $this->sorted = true;
+ \asort($this->schedule);
+ }
+
+ return \reset($this->schedule);
+ }
+
+ public function isEmpty()
+ {
+ return \count($this->timers) === 0;
+ }
+
+ public function tick()
+ {
+ // hot path: skip timers if nothing is scheduled
+ if (!$this->schedule) {
+ return;
+ }
+
+ // ensure timers are sorted so we can execute in order
+ if (!$this->sorted) {
+ $this->sorted = true;
+ \asort($this->schedule);
+ }
+
+ $time = $this->updateTime();
+
+ foreach ($this->schedule as $id => $scheduled) {
+ // schedule is ordered, so loop until first timer that is not scheduled for execution now
+ if ($scheduled >= $time) {
+ break;
+ }
+
+ // skip any timers that are removed while we process the current schedule
+ if (!isset($this->schedule[$id]) || $this->schedule[$id] !== $scheduled) {
+ continue;
+ }
+
+ $timer = $this->timers[$id];
+ \call_user_func($timer->getCallback(), $timer);
+
+ // re-schedule if this is a periodic timer and it has not been cancelled explicitly already
+ if ($timer->isPeriodic() && isset($this->timers[$id])) {
+ $this->schedule[$id] = $timer->getInterval() + $time;
+ $this->sorted = false;
+ } else {
+ unset($this->timers[$id], $this->schedule[$id]);
+ }
+ }
+ }
+}
diff --git a/vendor/react/event-loop/src/TimerInterface.php b/vendor/react/event-loop/src/TimerInterface.php
new file mode 100644
index 0000000..cdcf773
--- /dev/null
+++ b/vendor/react/event-loop/src/TimerInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace React\EventLoop;
+
+interface TimerInterface
+{
+ /**
+ * Get the interval after which this timer will execute, in seconds
+ *
+ * @return float
+ */
+ public function getInterval();
+
+ /**
+ * Get the callback that will be executed when this timer elapses
+ *
+ * @return callable
+ */
+ public function getCallback();
+
+ /**
+ * Determine whether the time is periodic
+ *
+ * @return bool
+ */
+ public function isPeriodic();
+}
diff --git a/vendor/react/http-client/LICENSE b/vendor/react/http-client/LICENSE
new file mode 100644
index 0000000..a808108
--- /dev/null
+++ b/vendor/react/http-client/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Igor Wiedler, Chris Boden
+
+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/react/http-client/composer.json b/vendor/react/http-client/composer.json
new file mode 100644
index 0000000..9207639
--- /dev/null
+++ b/vendor/react/http-client/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "react/http-client",
+ "description": "Event-driven, streaming HTTP client for ReactPHP",
+ "keywords": ["http"],
+ "license": "MIT",
+ "require": {
+ "php": ">=5.3.0",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/socket": "^1.0 || ^0.8.4",
+ "react/stream": "^1.0 || ^0.7.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.1"
+ },
+ "autoload": {
+ "psr-4": {
+ "React\\HttpClient\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Tests\\HttpClient\\": "tests"
+ }
+ }
+}
diff --git a/vendor/react/http-client/src/ChunkedStreamDecoder.php b/vendor/react/http-client/src/ChunkedStreamDecoder.php
new file mode 100644
index 0000000..bc150ad
--- /dev/null
+++ b/vendor/react/http-client/src/ChunkedStreamDecoder.php
@@ -0,0 +1,207 @@
+<?php
+
+namespace React\HttpClient;
+
+use Evenement\EventEmitter;
+use Exception;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @internal
+ */
+class ChunkedStreamDecoder extends EventEmitter implements ReadableStreamInterface
+{
+ const CRLF = "\r\n";
+
+ /**
+ * @var string
+ */
+ protected $buffer = '';
+
+ /**
+ * @var int
+ */
+ protected $remainingLength = 0;
+
+ /**
+ * @var bool
+ */
+ protected $nextChunkIsLength = true;
+
+ /**
+ * @var ReadableStreamInterface
+ */
+ protected $stream;
+
+ /**
+ * @var bool
+ */
+ protected $closed = false;
+
+ /**
+ * @var bool
+ */
+ protected $reachedEnd = false;
+
+ /**
+ * @param ReadableStreamInterface $stream
+ */
+ public function __construct(ReadableStreamInterface $stream)
+ {
+ $this->stream = $stream;
+ $this->stream->on('data', array($this, 'handleData'));
+ $this->stream->on('end', array($this, 'handleEnd'));
+ Util::forwardEvents($this->stream, $this, array(
+ 'error',
+ ));
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ do {
+ $bufferLength = strlen($this->buffer);
+ $continue = $this->iterateBuffer();
+ $iteratedBufferLength = strlen($this->buffer);
+ } while (
+ $continue &&
+ $bufferLength !== $iteratedBufferLength &&
+ $iteratedBufferLength > 0
+ );
+
+ if ($this->buffer === false) {
+ $this->buffer = '';
+ }
+ }
+
+ protected function iterateBuffer()
+ {
+ if (strlen($this->buffer) <= 1) {
+ return false;
+ }
+
+ if ($this->nextChunkIsLength) {
+ $crlfPosition = strpos($this->buffer, static::CRLF);
+ if ($crlfPosition === false && strlen($this->buffer) > 1024) {
+ $this->emit('error', array(
+ new Exception('Chunk length header longer then 1024 bytes'),
+ ));
+ $this->close();
+ return false;
+ }
+ if ($crlfPosition === false) {
+ return false; // Chunk header hasn't completely come in yet
+ }
+ $lengthChunk = substr($this->buffer, 0, $crlfPosition);
+ if (strpos($lengthChunk, ';') !== false) {
+ list($lengthChunk) = explode(';', $lengthChunk, 2);
+ }
+ if ($lengthChunk !== '') {
+ $lengthChunk = ltrim(trim($lengthChunk), "0");
+ if ($lengthChunk === '') {
+ // We've reached the end of the stream
+ $this->reachedEnd = true;
+ $this->emit('end');
+ $this->close();
+ return false;
+ }
+ }
+ $this->nextChunkIsLength = false;
+ if (dechex((int)@hexdec($lengthChunk)) !== strtolower($lengthChunk)) {
+ $this->emit('error', array(
+ new Exception('Unable to validate "' . $lengthChunk . '" as chunk length header'),
+ ));
+ $this->close();
+ return false;
+ }
+ $this->remainingLength = hexdec($lengthChunk);
+ $this->buffer = substr($this->buffer, $crlfPosition + 2);
+ return true;
+ }
+
+ if ($this->remainingLength > 0) {
+ $chunkLength = $this->getChunkLength();
+ if ($chunkLength === 0) {
+ return true;
+ }
+ $this->emit('data', array(
+ substr($this->buffer, 0, $chunkLength),
+ $this
+ ));
+ $this->remainingLength -= $chunkLength;
+ $this->buffer = substr($this->buffer, $chunkLength);
+ return true;
+ }
+
+ $this->nextChunkIsLength = true;
+ $this->buffer = substr($this->buffer, 2);
+ return true;
+ }
+
+ protected function getChunkLength()
+ {
+ $bufferLength = strlen($this->buffer);
+
+ if ($bufferLength >= $this->remainingLength) {
+ return $this->remainingLength;
+ }
+
+ return $bufferLength;
+ }
+
+ public function pause()
+ {
+ $this->stream->pause();
+ }
+
+ public function resume()
+ {
+ $this->stream->resume();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ $this->closed = true;
+ return $this->stream->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->handleData('');
+
+ if ($this->closed) {
+ return;
+ }
+
+ if ($this->buffer === '' && $this->reachedEnd) {
+ $this->emit('end');
+ $this->close();
+ return;
+ }
+
+ $this->emit(
+ 'error',
+ array(
+ new Exception('Stream ended with incomplete control code')
+ )
+ );
+ $this->close();
+ }
+}
diff --git a/vendor/react/http-client/src/Client.php b/vendor/react/http-client/src/Client.php
new file mode 100644
index 0000000..fc14426
--- /dev/null
+++ b/vendor/react/http-client/src/Client.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace React\HttpClient;
+
+use React\EventLoop\LoopInterface;
+use React\Socket\ConnectorInterface;
+use React\Socket\Connector;
+
+class Client
+{
+ private $connector;
+
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null)
+ {
+ if ($connector === null) {
+ $connector = new Connector($loop);
+ }
+
+ $this->connector = $connector;
+ }
+
+ public function request($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $requestData = new RequestData($method, $url, $headers, $protocolVersion);
+
+ return new Request($this->connector, $requestData);
+ }
+}
diff --git a/vendor/react/http-client/src/Request.php b/vendor/react/http-client/src/Request.php
new file mode 100644
index 0000000..caa242b
--- /dev/null
+++ b/vendor/react/http-client/src/Request.php
@@ -0,0 +1,294 @@
+<?php
+
+namespace React\HttpClient;
+
+use Evenement\EventEmitter;
+use React\Promise;
+use React\Socket\ConnectionInterface;
+use React\Socket\ConnectorInterface;
+use React\Stream\WritableStreamInterface;
+use RingCentral\Psr7 as gPsr;
+
+/**
+ * @event response
+ * @event drain
+ * @event error
+ * @event end
+ */
+class Request extends EventEmitter implements WritableStreamInterface
+{
+ const STATE_INIT = 0;
+ const STATE_WRITING_HEAD = 1;
+ const STATE_HEAD_WRITTEN = 2;
+ const STATE_END = 3;
+
+ private $connector;
+ private $requestData;
+
+ private $stream;
+ private $buffer;
+ private $responseFactory;
+ private $state = self::STATE_INIT;
+ private $ended = false;
+
+ private $pendingWrites = '';
+
+ public function __construct(ConnectorInterface $connector, RequestData $requestData)
+ {
+ $this->connector = $connector;
+ $this->requestData = $requestData;
+ }
+
+ public function isWritable()
+ {
+ return self::STATE_END > $this->state && !$this->ended;
+ }
+
+ private function writeHead()
+ {
+ $this->state = self::STATE_WRITING_HEAD;
+
+ $requestData = $this->requestData;
+ $streamRef = &$this->stream;
+ $stateRef = &$this->state;
+ $pendingWrites = &$this->pendingWrites;
+ $that = $this;
+
+ $promise = $this->connect();
+ $promise->then(
+ function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites, $that) {
+ $streamRef = $stream;
+
+ $stream->on('drain', array($that, 'handleDrain'));
+ $stream->on('data', array($that, 'handleData'));
+ $stream->on('end', array($that, 'handleEnd'));
+ $stream->on('error', array($that, 'handleError'));
+ $stream->on('close', array($that, 'handleClose'));
+
+ $headers = (string) $requestData;
+
+ $more = $stream->write($headers . $pendingWrites);
+
+ $stateRef = Request::STATE_HEAD_WRITTEN;
+
+ // clear pending writes if non-empty
+ if ($pendingWrites !== '') {
+ $pendingWrites = '';
+
+ if ($more) {
+ $that->emit('drain');
+ }
+ }
+ },
+ array($this, 'closeError')
+ );
+
+ $this->on('close', function() use ($promise) {
+ $promise->cancel();
+ });
+ }
+
+ public function write($data)
+ {
+ if (!$this->isWritable()) {
+ return false;
+ }
+
+ // write directly to connection stream if already available
+ if (self::STATE_HEAD_WRITTEN <= $this->state) {
+ return $this->stream->write($data);
+ }
+
+ // otherwise buffer and try to establish connection
+ $this->pendingWrites .= $data;
+ if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ return false;
+ }
+
+ public function end($data = null)
+ {
+ if (!$this->isWritable()) {
+ return;
+ }
+
+ if (null !== $data) {
+ $this->write($data);
+ } else if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ $this->ended = true;
+ }
+
+ /** @internal */
+ public function handleDrain()
+ {
+ $this->emit('drain');
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ // buffer until double CRLF (or double LF for compatibility with legacy servers)
+ if (false !== strpos($this->buffer, "\r\n\r\n") || false !== strpos($this->buffer, "\n\n")) {
+ try {
+ list($response, $bodyChunk) = $this->parseResponse($this->buffer);
+ } catch (\InvalidArgumentException $exception) {
+ $this->emit('error', array($exception));
+ }
+
+ $this->buffer = null;
+
+ $this->stream->removeListener('drain', array($this, 'handleDrain'));
+ $this->stream->removeListener('data', array($this, 'handleData'));
+ $this->stream->removeListener('end', array($this, 'handleEnd'));
+ $this->stream->removeListener('error', array($this, 'handleError'));
+ $this->stream->removeListener('close', array($this, 'handleClose'));
+
+ if (!isset($response)) {
+ return;
+ }
+
+ $response->on('close', array($this, 'close'));
+ $that = $this;
+ $response->on('error', function (\Exception $error) use ($that) {
+ $that->closeError(new \RuntimeException(
+ "An error occured in the response",
+ 0,
+ $error
+ ));
+ });
+
+ $this->emit('response', array($response, $this));
+
+ $this->stream->emit('data', array($bodyChunk));
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->closeError(new \RuntimeException(
+ "Connection ended before receiving response"
+ ));
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->closeError(new \RuntimeException(
+ "An error occurred in the underlying stream",
+ 0,
+ $error
+ ));
+ }
+
+ /** @internal */
+ public function handleClose()
+ {
+ $this->close();
+ }
+
+ /** @internal */
+ public function closeError(\Exception $error)
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+ $this->emit('error', array($error));
+ $this->close();
+ }
+
+ public function close()
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+
+ $this->state = self::STATE_END;
+ $this->pendingWrites = '';
+
+ if ($this->stream) {
+ $this->stream->close();
+ }
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ protected function parseResponse($data)
+ {
+ $psrResponse = gPsr\parse_response($data);
+ $headers = array_map(function($val) {
+ if (1 === count($val)) {
+ $val = $val[0];
+ }
+
+ return $val;
+ }, $psrResponse->getHeaders());
+
+ $factory = $this->getResponseFactory();
+
+ $response = $factory(
+ 'HTTP',
+ $psrResponse->getProtocolVersion(),
+ $psrResponse->getStatusCode(),
+ $psrResponse->getReasonPhrase(),
+ $headers
+ );
+
+ return array($response, (string)($psrResponse->getBody()));
+ }
+
+ protected function connect()
+ {
+ $scheme = $this->requestData->getScheme();
+ if ($scheme !== 'https' && $scheme !== 'http') {
+ return Promise\reject(
+ new \InvalidArgumentException('Invalid request URL given')
+ );
+ }
+
+ $host = $this->requestData->getHost();
+ $port = $this->requestData->getPort();
+
+ if ($scheme === 'https') {
+ $host = 'tls://' . $host;
+ }
+
+ return $this->connector
+ ->connect($host . ':' . $port);
+ }
+
+ public function setResponseFactory($factory)
+ {
+ $this->responseFactory = $factory;
+ }
+
+ public function getResponseFactory()
+ {
+ if (null === $factory = $this->responseFactory) {
+ $stream = $this->stream;
+
+ $factory = function ($protocol, $version, $code, $reasonPhrase, $headers) use ($stream) {
+ return new Response(
+ $stream,
+ $protocol,
+ $version,
+ $code,
+ $reasonPhrase,
+ $headers
+ );
+ };
+
+ $this->responseFactory = $factory;
+ }
+
+ return $factory;
+ }
+}
diff --git a/vendor/react/http-client/src/RequestData.php b/vendor/react/http-client/src/RequestData.php
new file mode 100644
index 0000000..1c7d5eb
--- /dev/null
+++ b/vendor/react/http-client/src/RequestData.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace React\HttpClient;
+
+class RequestData
+{
+ private $method;
+ private $url;
+ private $headers;
+ private $protocolVersion;
+
+ public function __construct($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $this->method = $method;
+ $this->url = $url;
+ $this->headers = $headers;
+ $this->protocolVersion = $protocolVersion;
+ }
+
+ private function mergeDefaultheaders(array $headers)
+ {
+ $port = ($this->getDefaultPort() === $this->getPort()) ? '' : ":{$this->getPort()}";
+ $connectionHeaders = ('1.1' === $this->protocolVersion) ? array('Connection' => 'close') : array();
+ $authHeaders = $this->getAuthHeaders();
+
+ $defaults = array_merge(
+ array(
+ 'Host' => $this->getHost().$port,
+ 'User-Agent' => 'React/alpha',
+ ),
+ $connectionHeaders,
+ $authHeaders
+ );
+
+ // remove all defaults that already exist in $headers
+ $lower = array_change_key_case($headers, CASE_LOWER);
+ foreach ($defaults as $key => $_) {
+ if (isset($lower[strtolower($key)])) {
+ unset($defaults[$key]);
+ }
+ }
+
+ return array_merge($defaults, $headers);
+ }
+
+ public function getScheme()
+ {
+ return parse_url($this->url, PHP_URL_SCHEME);
+ }
+
+ public function getHost()
+ {
+ return parse_url($this->url, PHP_URL_HOST);
+ }
+
+ public function getPort()
+ {
+ return (int) parse_url($this->url, PHP_URL_PORT) ?: $this->getDefaultPort();
+ }
+
+ public function getDefaultPort()
+ {
+ return ('https' === $this->getScheme()) ? 443 : 80;
+ }
+
+ public function getPath()
+ {
+ $path = parse_url($this->url, PHP_URL_PATH);
+ $queryString = parse_url($this->url, PHP_URL_QUERY);
+
+ // assume "/" path by default, but allow "OPTIONS *"
+ if ($path === null) {
+ $path = ($this->method === 'OPTIONS' && $queryString === null) ? '*': '/';
+ }
+ if ($queryString !== null) {
+ $path .= '?' . $queryString;
+ }
+
+ return $path;
+ }
+
+ public function setProtocolVersion($version)
+ {
+ $this->protocolVersion = $version;
+ }
+
+ public function __toString()
+ {
+ $headers = $this->mergeDefaultheaders($this->headers);
+
+ $data = '';
+ $data .= "{$this->method} {$this->getPath()} HTTP/{$this->protocolVersion}\r\n";
+ foreach ($headers as $name => $values) {
+ foreach ((array)$values as $value) {
+ $data .= "$name: $value\r\n";
+ }
+ }
+ $data .= "\r\n";
+
+ return $data;
+ }
+
+ private function getUrlUserPass()
+ {
+ $components = parse_url($this->url);
+
+ if (isset($components['user'])) {
+ return array(
+ 'user' => $components['user'],
+ 'pass' => isset($components['pass']) ? $components['pass'] : null,
+ );
+ }
+ }
+
+ private function getAuthHeaders()
+ {
+ if (null !== $auth = $this->getUrlUserPass()) {
+ return array(
+ 'Authorization' => 'Basic ' . base64_encode($auth['user'].':'.$auth['pass']),
+ );
+ }
+
+ return array();
+ }
+}
diff --git a/vendor/react/http-client/src/Response.php b/vendor/react/http-client/src/Response.php
new file mode 100644
index 0000000..5ed271f
--- /dev/null
+++ b/vendor/react/http-client/src/Response.php
@@ -0,0 +1,174 @@
+<?php
+
+namespace React\HttpClient;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @event data ($bodyChunk)
+ * @event error
+ * @event end
+ */
+class Response extends EventEmitter implements ReadableStreamInterface
+{
+ private $stream;
+ private $protocol;
+ private $version;
+ private $code;
+ private $reasonPhrase;
+ private $headers;
+ private $readable = true;
+
+ public function __construct(ReadableStreamInterface $stream, $protocol, $version, $code, $reasonPhrase, $headers)
+ {
+ $this->stream = $stream;
+ $this->protocol = $protocol;
+ $this->version = $version;
+ $this->code = $code;
+ $this->reasonPhrase = $reasonPhrase;
+ $this->headers = $headers;
+
+ if (strtolower($this->getHeaderLine('Transfer-Encoding')) === 'chunked') {
+ $this->stream = new ChunkedStreamDecoder($stream);
+ $this->removeHeader('Transfer-Encoding');
+ }
+
+ $this->stream->on('data', array($this, 'handleData'));
+ $this->stream->on('error', array($this, 'handleError'));
+ $this->stream->on('end', array($this, 'handleEnd'));
+ $this->stream->on('close', array($this, 'handleClose'));
+ }
+
+ public function getProtocol()
+ {
+ return $this->protocol;
+ }
+
+ public function getVersion()
+ {
+ return $this->version;
+ }
+
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ private function removeHeader($name)
+ {
+ foreach ($this->headers as $key => $value) {
+ if (strcasecmp($name, $key) === 0) {
+ unset($this->headers[$key]);
+ break;
+ }
+ }
+ }
+
+ private function getHeader($name)
+ {
+ $name = strtolower($name);
+ $normalized = array_change_key_case($this->headers, CASE_LOWER);
+
+ return isset($normalized[$name]) ? (array)$normalized[$name] : array();
+ }
+
+ private function getHeaderLine($name)
+ {
+ return implode(', ' , $this->getHeader($name));
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ if ($this->readable) {
+ $this->emit('data', array($data));
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if (!$this->readable) {
+ return;
+ }
+ $this->emit('end');
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ if (!$this->readable) {
+ return;
+ }
+ $this->emit('error', array(new \RuntimeException(
+ "An error occurred in the underlying stream",
+ 0,
+ $error
+ )));
+
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleClose()
+ {
+ $this->close();
+ }
+
+ public function close()
+ {
+ if (!$this->readable) {
+ return;
+ }
+
+ $this->readable = false;
+ $this->stream->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function pause()
+ {
+ if (!$this->readable) {
+ return;
+ }
+
+ $this->stream->pause();
+ }
+
+ public function resume()
+ {
+ if (!$this->readable) {
+ return;
+ }
+
+ $this->stream->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+}
diff --git a/vendor/react/http/LICENSE b/vendor/react/http/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/http/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/http/composer.json b/vendor/react/http/composer.json
new file mode 100644
index 0000000..4c9a038
--- /dev/null
+++ b/vendor/react/http/composer.json
@@ -0,0 +1,53 @@
+{
+ "name": "react/http",
+ "description": "Event-driven, streaming HTTP client and server implementation for ReactPHP",
+ "keywords": ["HTTP client", "HTTP server", "HTTP", "HTTPS", "event-driven", "streaming", "client", "server", "PSR-7", "async", "ReactPHP"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "fig/http-message-util": "^1.1",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.3 || ^1.2.1",
+ "react/promise-stream": "^1.1",
+ "react/socket": "^1.9",
+ "react/stream": "^1.2",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "clue/http-proxy-react": "^1.7",
+ "clue/reactphp-ssh-proxy": "^1.3",
+ "clue/socks-react": "^1.3",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "autoload": {
+ "psr-4": { "React\\Http\\": "src" }
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\Http\\": "tests" }
+ }
+}
diff --git a/vendor/react/http/src/Browser.php b/vendor/react/http/src/Browser.php
new file mode 100644
index 0000000..72847f6
--- /dev/null
+++ b/vendor/react/http/src/Browser.php
@@ -0,0 +1,790 @@
+<?php
+
+namespace React\Http;
+
+use Psr\Http\Message\ResponseInterface;
+use RingCentral\Psr7\Request;
+use RingCentral\Psr7\Uri;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Http\Io\ReadableBodyStream;
+use React\Http\Io\Sender;
+use React\Http\Io\Transaction;
+use React\Promise\PromiseInterface;
+use React\Socket\ConnectorInterface;
+use React\Stream\ReadableStreamInterface;
+use InvalidArgumentException;
+
+/**
+ * @final This class is final and shouldn't be extended as it is likely to be marked final in a future release.
+ */
+class Browser
+{
+ private $transaction;
+ private $baseUrl;
+ private $protocolVersion = '1.1';
+
+ /**
+ * The `Browser` is responsible for sending HTTP requests to your HTTP server
+ * and keeps track of pending incoming HTTP responses.
+ *
+ * ```php
+ * $browser = new React\Http\Browser();
+ * ```
+ *
+ * This class takes two optional arguments for more advanced usage:
+ *
+ * ```php
+ * // constructor signature as of v1.5.0
+ * $browser = new React\Http\Browser(?ConnectorInterface $connector = null, ?LoopInterface $loop = null);
+ *
+ * // legacy constructor signature before v1.5.0
+ * $browser = new React\Http\Browser(?LoopInterface $loop = null, ?ConnectorInterface $connector = null);
+ * ```
+ *
+ * If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
+ * proxy servers etc.), you can explicitly pass a custom instance of the
+ * [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface):
+ *
+ * ```php
+ * $connector = new React\Socket\Connector(array(
+ * 'dns' => '127.0.0.1',
+ * 'tcp' => array(
+ * 'bindto' => '192.168.10.1:0'
+ * ),
+ * 'tls' => array(
+ * 'verify_peer' => false,
+ * 'verify_peer_name' => false
+ * )
+ * ));
+ *
+ * $browser = new React\Http\Browser($connector);
+ * ```
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param null|ConnectorInterface|LoopInterface $connector
+ * @param null|LoopInterface|ConnectorInterface $loop
+ * @throws \InvalidArgumentException for invalid arguments
+ */
+ public function __construct($connector = null, $loop = null)
+ {
+ // swap arguments for legacy constructor signature
+ if (($connector instanceof LoopInterface || $connector === null) && ($loop instanceof ConnectorInterface || $loop === null)) {
+ $swap = $loop;
+ $loop = $connector;
+ $connector = $swap;
+ }
+
+ if (($connector !== null && !$connector instanceof ConnectorInterface) || ($loop !== null && !$loop instanceof LoopInterface)) {
+ throw new \InvalidArgumentException('Expected "?ConnectorInterface $connector" and "?LoopInterface $loop" arguments');
+ }
+
+ $loop = $loop ?: Loop::get();
+ $this->transaction = new Transaction(
+ Sender::createFromLoop($loop, $connector),
+ $loop
+ );
+ }
+
+ /**
+ * Sends an HTTP GET request
+ *
+ * ```php
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [GET request client example](../examples/01-client-get-request.php).
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function get($url, array $headers = array())
+ {
+ return $this->requestMayBeStreaming('GET', $url, $headers);
+ }
+
+ /**
+ * Sends an HTTP POST request
+ *
+ * ```php
+ * $browser->post(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/json'
+ * ],
+ * json_encode($data)
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump(json_decode((string)$response->getBody()));
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [POST JSON client example](../examples/04-client-post-json.php).
+ *
+ * This method is also commonly used to submit HTML form data:
+ *
+ * ```php
+ * $data = [
+ * 'user' => 'Alice',
+ * 'password' => 'secret'
+ * ];
+ *
+ * $browser->post(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/x-www-form-urlencoded'
+ * ],
+ * http_build_query($data)
+ * );
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * Loop::addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->post($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $body
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function post($url, array $headers = array(), $body = '')
+ {
+ return $this->requestMayBeStreaming('POST', $url, $headers, $body);
+ }
+
+ /**
+ * Sends an HTTP HEAD request
+ *
+ * ```php
+ * $browser->head($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump($response->getHeaders());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function head($url, array $headers = array())
+ {
+ return $this->requestMayBeStreaming('HEAD', $url, $headers);
+ }
+
+ /**
+ * Sends an HTTP PATCH request
+ *
+ * ```php
+ * $browser->patch(
+ * $url,
+ * [
+ * 'Content-Type' => 'application/json'
+ * ],
+ * json_encode($data)
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump(json_decode((string)$response->getBody()));
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * Loop::addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->patch($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $body
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function patch($url, array $headers = array(), $body = '')
+ {
+ return $this->requestMayBeStreaming('PATCH', $url , $headers, $body);
+ }
+
+ /**
+ * Sends an HTTP PUT request
+ *
+ * ```php
+ * $browser->put(
+ * $url,
+ * [
+ * 'Content-Type' => 'text/xml'
+ * ],
+ * $xml->asXML()
+ * )->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [PUT XML client example](../examples/05-client-put-xml.php).
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the outgoing request body is a `string`. If you're using a
+ * streaming request body (`ReadableStreamInterface`), it will default to
+ * using `Transfer-Encoding: chunked` or you have to explicitly pass in a
+ * matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * Loop::addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->put($url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $body
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function put($url, array $headers = array(), $body = '')
+ {
+ return $this->requestMayBeStreaming('PUT', $url, $headers, $body);
+ }
+
+ /**
+ * Sends an HTTP DELETE request
+ *
+ * ```php
+ * $browser->delete($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * @param string $url URL for the request.
+ * @param array $headers
+ * @param string|ReadableStreamInterface $body
+ * @return PromiseInterface<ResponseInterface>
+ */
+ public function delete($url, array $headers = array(), $body = '')
+ {
+ return $this->requestMayBeStreaming('DELETE', $url, $headers, $body);
+ }
+
+ /**
+ * Sends an arbitrary HTTP request.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request.
+ *
+ * As an alternative, if you want to use a custom HTTP request method, you
+ * can use this method:
+ *
+ * ```php
+ * $browser->request('OPTIONS', $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * var_dump((string)$response->getBody());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the size of the outgoing request body is known and non-empty.
+ * For an empty request body, if will only include a `Content-Length: 0`
+ * request header if the request method usually expects a request body (only
+ * applies to `POST`, `PUT` and `PATCH`).
+ *
+ * If you're using a streaming request body (`ReadableStreamInterface`), it
+ * will default to using `Transfer-Encoding: chunked` or you have to
+ * explicitly pass in a matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * Loop::addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->request('POST', $url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * @param string $method HTTP request method, e.g. GET/HEAD/POST etc.
+ * @param string $url URL for the request
+ * @param array $headers Additional request headers
+ * @param string|ReadableStreamInterface $body HTTP request body contents
+ * @return PromiseInterface<ResponseInterface,\Exception>
+ */
+ public function request($method, $url, array $headers = array(), $body = '')
+ {
+ return $this->withOptions(array('streaming' => false))->requestMayBeStreaming($method, $url, $headers, $body);
+ }
+
+ /**
+ * Sends an arbitrary HTTP request and receives a streaming response without buffering the response body.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request. Each of these methods will buffer
+ * the whole response body in memory by default. This is easy to get started
+ * and works reasonably well for smaller responses.
+ *
+ * In some situations, it's a better idea to use a streaming approach, where
+ * only small chunks have to be kept in memory. You can use this method to
+ * send an arbitrary HTTP request and receive a streaming response. It uses
+ * the same HTTP message API, but does not buffer the response body in
+ * memory. It only processes the response body in small chunks as data is
+ * received and forwards this data through [ReactPHP's Stream API](https://github.com/reactphp/stream).
+ * This works for (any number of) responses of arbitrary sizes.
+ *
+ * ```php
+ * $browser->requestStreaming('GET', $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * $body = $response->getBody();
+ * assert($body instanceof Psr\Http\Message\StreamInterface);
+ * assert($body instanceof React\Stream\ReadableStreamInterface);
+ *
+ * $body->on('data', function ($chunk) {
+ * echo $chunk;
+ * });
+ *
+ * $body->on('error', function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ *
+ * $body->on('close', function () {
+ * echo '[DONE]' . PHP_EOL;
+ * });
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also [`ReadableStreamInterface`](https://github.com/reactphp/stream#readablestreaminterface)
+ * and the [streaming response](#streaming-response) for more details,
+ * examples and possible use-cases.
+ *
+ * This method will automatically add a matching `Content-Length` request
+ * header if the size of the outgoing request body is known and non-empty.
+ * For an empty request body, if will only include a `Content-Length: 0`
+ * request header if the request method usually expects a request body (only
+ * applies to `POST`, `PUT` and `PATCH`).
+ *
+ * If you're using a streaming request body (`ReadableStreamInterface`), it
+ * will default to using `Transfer-Encoding: chunked` or you have to
+ * explicitly pass in a matching `Content-Length` request header like so:
+ *
+ * ```php
+ * $body = new React\Stream\ThroughStream();
+ * Loop::addTimer(1.0, function () use ($body) {
+ * $body->end("hello world");
+ * });
+ *
+ * $browser->requestStreaming('POST', $url, array('Content-Length' => '11'), $body);
+ * ```
+ *
+ * @param string $method HTTP request method, e.g. GET/HEAD/POST etc.
+ * @param string $url URL for the request
+ * @param array $headers Additional request headers
+ * @param string|ReadableStreamInterface $body HTTP request body contents
+ * @return PromiseInterface<ResponseInterface,\Exception>
+ */
+ public function requestStreaming($method, $url, $headers = array(), $body = '')
+ {
+ return $this->withOptions(array('streaming' => true))->requestMayBeStreaming($method, $url, $headers, $body);
+ }
+
+ /**
+ * Changes the maximum timeout used for waiting for pending requests.
+ *
+ * You can pass in the number of seconds to use as a new timeout value:
+ *
+ * ```php
+ * $browser = $browser->withTimeout(10.0);
+ * ```
+ *
+ * You can pass in a bool `false` to disable any timeouts. In this case,
+ * requests can stay pending forever:
+ *
+ * ```php
+ * $browser = $browser->withTimeout(false);
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default timeout handling. This
+ * will respects PHP's `default_socket_timeout` setting (default 60s):
+ *
+ * ```php
+ * $browser = $browser->withTimeout(true);
+ * ```
+ *
+ * See also [timeouts](#timeouts) for more details about timeout handling.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given timeout value applied.
+ *
+ * @param bool|number $timeout
+ * @return self
+ */
+ public function withTimeout($timeout)
+ {
+ if ($timeout === true) {
+ $timeout = null;
+ } elseif ($timeout === false) {
+ $timeout = -1;
+ } elseif ($timeout < 0) {
+ $timeout = 0;
+ }
+
+ return $this->withOptions(array(
+ 'timeout' => $timeout,
+ ));
+ }
+
+ /**
+ * Changes how HTTP redirects will be followed.
+ *
+ * You can pass in the maximum number of redirects to follow:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(5);
+ * ```
+ *
+ * The request will automatically be rejected when the number of redirects
+ * is exceeded. You can pass in a `0` to reject the request for any
+ * redirects encountered:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(0);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // only non-redirected responses will now end up here
+ * var_dump($response->getHeaders());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * You can pass in a bool `false` to disable following any redirects. In
+ * this case, requests will resolve with the redirection response instead
+ * of following the `Location` response header:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(false);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any redirects will now end up here
+ * var_dump($response->getHeaderLine('Location'));
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default redirect handling.
+ * This defaults to following a maximum of 10 redirects:
+ *
+ * ```php
+ * $browser = $browser->withFollowRedirects(true);
+ * ```
+ *
+ * See also [redirects](#redirects) for more details about redirect handling.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given redirect setting applied.
+ *
+ * @param bool|int $followRedirects
+ * @return self
+ */
+ public function withFollowRedirects($followRedirects)
+ {
+ return $this->withOptions(array(
+ 'followRedirects' => $followRedirects !== false,
+ 'maxRedirects' => \is_bool($followRedirects) ? null : $followRedirects
+ ));
+ }
+
+ /**
+ * Changes whether non-successful HTTP response status codes (4xx and 5xx) will be rejected.
+ *
+ * You can pass in a bool `false` to disable rejecting incoming responses
+ * that use a 4xx or 5xx response status code. In this case, requests will
+ * resolve with the response message indicating an error condition:
+ *
+ * ```php
+ * $browser = $browser->withRejectErrorResponse(false);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any HTTP response will now end up here
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * You can pass in a bool `true` to re-enable default status code handling.
+ * This defaults to rejecting any response status codes in the 4xx or 5xx
+ * range:
+ *
+ * ```php
+ * $browser = $browser->withRejectErrorResponse(true);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // any successful HTTP response will now end up here
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * }, function (Exception $e) {
+ * if ($e instanceof React\Http\Message\ResponseException) {
+ * // any HTTP response error message will now end up here
+ * $response = $e->getResponse();
+ * var_dump($response->getStatusCode(), $response->getReasonPhrase());
+ * } else {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * }
+ * });
+ * ```
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given setting applied.
+ *
+ * @param bool $obeySuccessCode
+ * @return self
+ */
+ public function withRejectErrorResponse($obeySuccessCode)
+ {
+ return $this->withOptions(array(
+ 'obeySuccessCode' => $obeySuccessCode,
+ ));
+ }
+
+ /**
+ * Changes the base URL used to resolve relative URLs to.
+ *
+ * If you configure a base URL, any requests to relative URLs will be
+ * processed by first resolving this relative to the given absolute base
+ * URL. This supports resolving relative path references (like `../` etc.).
+ * This is particularly useful for (RESTful) API calls where all endpoints
+ * (URLs) are located under a common base URL.
+ *
+ * ```php
+ * $browser = $browser->withBase('http://api.example.com/v3/');
+ *
+ * // will request http://api.example.com/v3/users
+ * $browser->get('users')->then(…);
+ * ```
+ *
+ * You can pass in a `null` base URL to return a new instance that does not
+ * use a base URL:
+ *
+ * ```php
+ * $browser = $browser->withBase(null);
+ * ```
+ *
+ * Accordingly, any requests using relative URLs to a browser that does not
+ * use a base URL can not be completed and will be rejected without sending
+ * a request.
+ *
+ * This method will throw an `InvalidArgumentException` if the given
+ * `$baseUrl` argument is not a valid URL.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. the `withBase()` method
+ * actually returns a *new* [`Browser`](#browser) instance with the given base URL applied.
+ *
+ * @param string|null $baseUrl absolute base URL
+ * @return self
+ * @throws InvalidArgumentException if the given $baseUrl is not a valid absolute URL
+ * @see self::withoutBase()
+ */
+ public function withBase($baseUrl)
+ {
+ $browser = clone $this;
+ if ($baseUrl === null) {
+ $browser->baseUrl = null;
+ return $browser;
+ }
+
+ $browser->baseUrl = new Uri($baseUrl);
+ if (!\in_array($browser->baseUrl->getScheme(), array('http', 'https')) || $browser->baseUrl->getHost() === '') {
+ throw new \InvalidArgumentException('Base URL must be absolute');
+ }
+
+ return $browser;
+ }
+
+ /**
+ * Changes the HTTP protocol version that will be used for all subsequent requests.
+ *
+ * All the above [request methods](#request-methods) default to sending
+ * requests as HTTP/1.1. This is the preferred HTTP protocol version which
+ * also provides decent backwards-compatibility with legacy HTTP/1.0
+ * servers. As such, there should rarely be a need to explicitly change this
+ * protocol version.
+ *
+ * If you want to explicitly use the legacy HTTP/1.0 protocol version, you
+ * can use this method:
+ *
+ * ```php
+ * $browser = $browser->withProtocolVersion('1.0');
+ *
+ * $browser->get($url)->then(…);
+ * ```
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * new protocol version applied.
+ *
+ * @param string $protocolVersion HTTP protocol version to use, must be one of "1.1" or "1.0"
+ * @return self
+ * @throws InvalidArgumentException
+ */
+ public function withProtocolVersion($protocolVersion)
+ {
+ if (!\in_array($protocolVersion, array('1.0', '1.1'), true)) {
+ throw new InvalidArgumentException('Invalid HTTP protocol version, must be one of "1.1" or "1.0"');
+ }
+
+ $browser = clone $this;
+ $browser->protocolVersion = (string) $protocolVersion;
+
+ return $browser;
+ }
+
+ /**
+ * Changes the maximum size for buffering a response body.
+ *
+ * The preferred way to send an HTTP request is by using the above
+ * [request methods](#request-methods), for example the [`get()`](#get)
+ * method to send an HTTP `GET` request. Each of these methods will buffer
+ * the whole response body in memory by default. This is easy to get started
+ * and works reasonably well for smaller responses.
+ *
+ * By default, the response body buffer will be limited to 16 MiB. If the
+ * response body exceeds this maximum size, the request will be rejected.
+ *
+ * You can pass in the maximum number of bytes to buffer:
+ *
+ * ```php
+ * $browser = $browser->withResponseBuffer(1024 * 1024);
+ *
+ * $browser->get($url)->then(function (Psr\Http\Message\ResponseInterface $response) {
+ * // response body will not exceed 1 MiB
+ * var_dump($response->getHeaders(), (string) $response->getBody());
+ * }, function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * Note that the response body buffer has to be kept in memory for each
+ * pending request until its transfer is completed and it will only be freed
+ * after a pending request is fulfilled. As such, increasing this maximum
+ * buffer size to allow larger response bodies is usually not recommended.
+ * Instead, you can use the [`requestStreaming()` method](#requeststreaming)
+ * to receive responses with arbitrary sizes without buffering. Accordingly,
+ * this maximum buffer size setting has no effect on streaming responses.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * given setting applied.
+ *
+ * @param int $maximumSize
+ * @return self
+ * @see self::requestStreaming()
+ */
+ public function withResponseBuffer($maximumSize)
+ {
+ return $this->withOptions(array(
+ 'maximumSize' => $maximumSize
+ ));
+ }
+
+ /**
+ * Changes the [options](#options) to use:
+ *
+ * The [`Browser`](#browser) class exposes several options for the handling of
+ * HTTP transactions. These options resemble some of PHP's
+ * [HTTP context options](http://php.net/manual/en/context.http.php) and
+ * can be controlled via the following API (and their defaults):
+ *
+ * ```php
+ * // deprecated
+ * $newBrowser = $browser->withOptions(array(
+ * 'timeout' => null, // see withTimeout() instead
+ * 'followRedirects' => true, // see withFollowRedirects() instead
+ * 'maxRedirects' => 10, // see withFollowRedirects() instead
+ * 'obeySuccessCode' => true, // see withRejectErrorResponse() instead
+ * 'streaming' => false, // deprecated, see requestStreaming() instead
+ * ));
+ * ```
+ *
+ * See also [timeouts](#timeouts), [redirects](#redirects) and
+ * [streaming](#streaming) for more details.
+ *
+ * Notice that the [`Browser`](#browser) is an immutable object, i.e. this
+ * method actually returns a *new* [`Browser`](#browser) instance with the
+ * options applied.
+ *
+ * @param array $options
+ * @return self
+ * @see self::withTimeout()
+ * @see self::withFollowRedirects()
+ * @see self::withRejectErrorResponse()
+ */
+ private function withOptions(array $options)
+ {
+ $browser = clone $this;
+ $browser->transaction = $this->transaction->withOptions($options);
+
+ return $browser;
+ }
+
+ /**
+ * @param string $method
+ * @param string $url
+ * @param array $headers
+ * @param string|ReadableStreamInterface $body
+ * @return PromiseInterface<ResponseInterface,\Exception>
+ */
+ private function requestMayBeStreaming($method, $url, array $headers = array(), $body = '')
+ {
+ if ($this->baseUrl !== null) {
+ // ensure we're actually below the base URL
+ $url = Uri::resolve($this->baseUrl, $url);
+ }
+
+ if ($body instanceof ReadableStreamInterface) {
+ $body = new ReadableBodyStream($body);
+ }
+
+ return $this->transaction->send(
+ new Request($method, $url, $headers, $body, $this->protocolVersion)
+ );
+ }
+}
diff --git a/vendor/react/http/src/Client/Client.php b/vendor/react/http/src/Client/Client.php
new file mode 100644
index 0000000..7a97349
--- /dev/null
+++ b/vendor/react/http/src/Client/Client.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace React\Http\Client;
+
+use React\EventLoop\LoopInterface;
+use React\Socket\ConnectorInterface;
+use React\Socket\Connector;
+
+/**
+ * @internal
+ */
+class Client
+{
+ private $connector;
+
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null)
+ {
+ if ($connector === null) {
+ $connector = new Connector(array(), $loop);
+ }
+
+ $this->connector = $connector;
+ }
+
+ public function request($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $requestData = new RequestData($method, $url, $headers, $protocolVersion);
+
+ return new Request($this->connector, $requestData);
+ }
+}
diff --git a/vendor/react/http/src/Client/Request.php b/vendor/react/http/src/Client/Request.php
new file mode 100644
index 0000000..51e0331
--- /dev/null
+++ b/vendor/react/http/src/Client/Request.php
@@ -0,0 +1,237 @@
+<?php
+
+namespace React\Http\Client;
+
+use Evenement\EventEmitter;
+use React\Promise;
+use React\Socket\ConnectionInterface;
+use React\Socket\ConnectorInterface;
+use React\Stream\WritableStreamInterface;
+use RingCentral\Psr7 as gPsr;
+
+/**
+ * @event response
+ * @event drain
+ * @event error
+ * @event end
+ * @internal
+ */
+class Request extends EventEmitter implements WritableStreamInterface
+{
+ const STATE_INIT = 0;
+ const STATE_WRITING_HEAD = 1;
+ const STATE_HEAD_WRITTEN = 2;
+ const STATE_END = 3;
+
+ private $connector;
+ private $requestData;
+
+ private $stream;
+ private $buffer;
+ private $responseFactory;
+ private $state = self::STATE_INIT;
+ private $ended = false;
+
+ private $pendingWrites = '';
+
+ public function __construct(ConnectorInterface $connector, RequestData $requestData)
+ {
+ $this->connector = $connector;
+ $this->requestData = $requestData;
+ }
+
+ public function isWritable()
+ {
+ return self::STATE_END > $this->state && !$this->ended;
+ }
+
+ private function writeHead()
+ {
+ $this->state = self::STATE_WRITING_HEAD;
+
+ $requestData = $this->requestData;
+ $streamRef = &$this->stream;
+ $stateRef = &$this->state;
+ $pendingWrites = &$this->pendingWrites;
+ $that = $this;
+
+ $promise = $this->connect();
+ $promise->then(
+ function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites, $that) {
+ $streamRef = $stream;
+
+ $stream->on('drain', array($that, 'handleDrain'));
+ $stream->on('data', array($that, 'handleData'));
+ $stream->on('end', array($that, 'handleEnd'));
+ $stream->on('error', array($that, 'handleError'));
+ $stream->on('close', array($that, 'handleClose'));
+
+ $headers = (string) $requestData;
+
+ $more = $stream->write($headers . $pendingWrites);
+
+ $stateRef = Request::STATE_HEAD_WRITTEN;
+
+ // clear pending writes if non-empty
+ if ($pendingWrites !== '') {
+ $pendingWrites = '';
+
+ if ($more) {
+ $that->emit('drain');
+ }
+ }
+ },
+ array($this, 'closeError')
+ );
+
+ $this->on('close', function() use ($promise) {
+ $promise->cancel();
+ });
+ }
+
+ public function write($data)
+ {
+ if (!$this->isWritable()) {
+ return false;
+ }
+
+ // write directly to connection stream if already available
+ if (self::STATE_HEAD_WRITTEN <= $this->state) {
+ return $this->stream->write($data);
+ }
+
+ // otherwise buffer and try to establish connection
+ $this->pendingWrites .= $data;
+ if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ return false;
+ }
+
+ public function end($data = null)
+ {
+ if (!$this->isWritable()) {
+ return;
+ }
+
+ if (null !== $data) {
+ $this->write($data);
+ } else if (self::STATE_WRITING_HEAD > $this->state) {
+ $this->writeHead();
+ }
+
+ $this->ended = true;
+ }
+
+ /** @internal */
+ public function handleDrain()
+ {
+ $this->emit('drain');
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ // buffer until double CRLF (or double LF for compatibility with legacy servers)
+ if (false !== strpos($this->buffer, "\r\n\r\n") || false !== strpos($this->buffer, "\n\n")) {
+ try {
+ $response = gPsr\parse_response($this->buffer);
+ $bodyChunk = (string) $response->getBody();
+ } catch (\InvalidArgumentException $exception) {
+ $this->emit('error', array($exception));
+ }
+
+ $this->buffer = null;
+
+ $this->stream->removeListener('drain', array($this, 'handleDrain'));
+ $this->stream->removeListener('data', array($this, 'handleData'));
+ $this->stream->removeListener('end', array($this, 'handleEnd'));
+ $this->stream->removeListener('error', array($this, 'handleError'));
+ $this->stream->removeListener('close', array($this, 'handleClose'));
+
+ if (!isset($response)) {
+ return;
+ }
+
+ $this->stream->on('close', array($this, 'handleClose'));
+
+ $this->emit('response', array($response, $this->stream));
+
+ $this->stream->emit('data', array($bodyChunk));
+ }
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->closeError(new \RuntimeException(
+ "Connection ended before receiving response"
+ ));
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->closeError(new \RuntimeException(
+ "An error occurred in the underlying stream",
+ 0,
+ $error
+ ));
+ }
+
+ /** @internal */
+ public function handleClose()
+ {
+ $this->close();
+ }
+
+ /** @internal */
+ public function closeError(\Exception $error)
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+ $this->emit('error', array($error));
+ $this->close();
+ }
+
+ public function close()
+ {
+ if (self::STATE_END <= $this->state) {
+ return;
+ }
+
+ $this->state = self::STATE_END;
+ $this->pendingWrites = '';
+
+ if ($this->stream) {
+ $this->stream->close();
+ }
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ protected function connect()
+ {
+ $scheme = $this->requestData->getScheme();
+ if ($scheme !== 'https' && $scheme !== 'http') {
+ return Promise\reject(
+ new \InvalidArgumentException('Invalid request URL given')
+ );
+ }
+
+ $host = $this->requestData->getHost();
+ $port = $this->requestData->getPort();
+
+ if ($scheme === 'https') {
+ $host = 'tls://' . $host;
+ }
+
+ return $this->connector
+ ->connect($host . ':' . $port);
+ }
+}
diff --git a/vendor/react/http/src/Client/RequestData.php b/vendor/react/http/src/Client/RequestData.php
new file mode 100644
index 0000000..a5908a0
--- /dev/null
+++ b/vendor/react/http/src/Client/RequestData.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace React\Http\Client;
+
+/**
+ * @internal
+ */
+class RequestData
+{
+ private $method;
+ private $url;
+ private $headers;
+ private $protocolVersion;
+
+ public function __construct($method, $url, array $headers = array(), $protocolVersion = '1.0')
+ {
+ $this->method = $method;
+ $this->url = $url;
+ $this->headers = $headers;
+ $this->protocolVersion = $protocolVersion;
+ }
+
+ private function mergeDefaultheaders(array $headers)
+ {
+ $port = ($this->getDefaultPort() === $this->getPort()) ? '' : ":{$this->getPort()}";
+ $connectionHeaders = ('1.1' === $this->protocolVersion) ? array('Connection' => 'close') : array();
+ $authHeaders = $this->getAuthHeaders();
+
+ $defaults = array_merge(
+ array(
+ 'Host' => $this->getHost().$port,
+ 'User-Agent' => 'ReactPHP/1',
+ ),
+ $connectionHeaders,
+ $authHeaders
+ );
+
+ // remove all defaults that already exist in $headers
+ $lower = array_change_key_case($headers, CASE_LOWER);
+ foreach ($defaults as $key => $_) {
+ if (isset($lower[strtolower($key)])) {
+ unset($defaults[$key]);
+ }
+ }
+
+ return array_merge($defaults, $headers);
+ }
+
+ public function getScheme()
+ {
+ return parse_url($this->url, PHP_URL_SCHEME);
+ }
+
+ public function getHost()
+ {
+ return parse_url($this->url, PHP_URL_HOST);
+ }
+
+ public function getPort()
+ {
+ return (int) parse_url($this->url, PHP_URL_PORT) ?: $this->getDefaultPort();
+ }
+
+ public function getDefaultPort()
+ {
+ return ('https' === $this->getScheme()) ? 443 : 80;
+ }
+
+ public function getPath()
+ {
+ $path = parse_url($this->url, PHP_URL_PATH);
+ $queryString = parse_url($this->url, PHP_URL_QUERY);
+
+ // assume "/" path by default, but allow "OPTIONS *"
+ if ($path === null) {
+ $path = ($this->method === 'OPTIONS' && $queryString === null) ? '*': '/';
+ }
+ if ($queryString !== null) {
+ $path .= '?' . $queryString;
+ }
+
+ return $path;
+ }
+
+ public function setProtocolVersion($version)
+ {
+ $this->protocolVersion = $version;
+ }
+
+ public function __toString()
+ {
+ $headers = $this->mergeDefaultheaders($this->headers);
+
+ $data = '';
+ $data .= "{$this->method} {$this->getPath()} HTTP/{$this->protocolVersion}\r\n";
+ foreach ($headers as $name => $values) {
+ foreach ((array)$values as $value) {
+ $data .= "$name: $value\r\n";
+ }
+ }
+ $data .= "\r\n";
+
+ return $data;
+ }
+
+ private function getUrlUserPass()
+ {
+ $components = parse_url($this->url);
+
+ if (isset($components['user'])) {
+ return array(
+ 'user' => $components['user'],
+ 'pass' => isset($components['pass']) ? $components['pass'] : null,
+ );
+ }
+ }
+
+ private function getAuthHeaders()
+ {
+ if (null !== $auth = $this->getUrlUserPass()) {
+ return array(
+ 'Authorization' => 'Basic ' . base64_encode($auth['user'].':'.$auth['pass']),
+ );
+ }
+
+ return array();
+ }
+}
diff --git a/vendor/react/http/src/HttpServer.php b/vendor/react/http/src/HttpServer.php
new file mode 100644
index 0000000..f233473
--- /dev/null
+++ b/vendor/react/http/src/HttpServer.php
@@ -0,0 +1,351 @@
+<?php
+
+namespace React\Http;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Http\Io\IniUtil;
+use React\Http\Io\MiddlewareRunner;
+use React\Http\Io\StreamingServer;
+use React\Http\Middleware\LimitConcurrentRequestsMiddleware;
+use React\Http\Middleware\StreamingRequestMiddleware;
+use React\Http\Middleware\RequestBodyBufferMiddleware;
+use React\Http\Middleware\RequestBodyParserMiddleware;
+use React\Socket\ServerInterface;
+
+/**
+ * The `React\Http\HttpServer` class is responsible for handling incoming connections and then
+ * processing each incoming HTTP request.
+ *
+ * When a complete HTTP request has been received, it will invoke the given
+ * request handler function. This request handler function needs to be passed to
+ * the constructor and will be invoked with the respective [request](#server-request)
+ * object and expects a [response](#server-response) object in return:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
+ * return new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * array(
+ * 'Content-Type' => 'text/plain'
+ * ),
+ * "Hello World!\n"
+ * );
+ * });
+ * ```
+ *
+ * Each incoming HTTP request message is always represented by the
+ * [PSR-7 `ServerRequestInterface`](https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface),
+ * see also following [request](#server-request) chapter for more details.
+ *
+ * Each outgoing HTTP response message is always represented by the
+ * [PSR-7 `ResponseInterface`](https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface),
+ * see also following [response](#server-response) chapter for more details.
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * In order to start listening for any incoming connections, the `HttpServer` needs
+ * to be attached to an instance of
+ * [`React\Socket\ServerInterface`](https://github.com/reactphp/socket#serverinterface)
+ * through the [`listen()`](#listen) method as described in the following
+ * chapter. In its most simple form, you can attach this to a
+ * [`React\Socket\SocketServer`](https://github.com/reactphp/socket#socketserver)
+ * in order to start a plaintext HTTP server like this:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer($handler);
+ *
+ * $socket = new React\Socket\SocketServer('0.0.0.0:8080');
+ * $http->listen($socket);
+ * ```
+ *
+ * See also the [`listen()`](#listen) method and
+ * [hello world server example](../examples/51-server-hello-world.php)
+ * for more details.
+ *
+ * By default, the `HttpServer` buffers and parses the complete incoming HTTP
+ * request in memory. It will invoke the given request handler function when the
+ * complete request headers and request body has been received. This means the
+ * [request](#server-request) object passed to your request handler function will be
+ * fully compatible with PSR-7 (http-message). This provides sane defaults for
+ * 80% of the use cases and is the recommended way to use this library unless
+ * you're sure you know what you're doing.
+ *
+ * On the other hand, buffering complete HTTP requests in memory until they can
+ * be processed by your request handler function means that this class has to
+ * employ a number of limits to avoid consuming too much memory. In order to
+ * take the more advanced configuration out your hand, it respects setting from
+ * your [`php.ini`](https://www.php.net/manual/en/ini.core.php) to apply its
+ * default settings. This is a list of PHP settings this class respects with
+ * their respective default values:
+ *
+ * ```
+ * memory_limit 128M
+ * post_max_size 8M // capped at 64K
+ *
+ * enable_post_data_reading 1
+ * max_input_nesting_level 64
+ * max_input_vars 1000
+ *
+ * file_uploads 1
+ * upload_max_filesize 2M
+ * max_file_uploads 20
+ * ```
+ *
+ * In particular, the `post_max_size` setting limits how much memory a single
+ * HTTP request is allowed to consume while buffering its request body. This
+ * needs to be limited because the server can process a large number of requests
+ * concurrently, so the server may potentially consume a large amount of memory
+ * otherwise. To support higher concurrency by default, this value is capped
+ * at `64K`. If you assign a higher value, it will only allow `64K` by default.
+ * If a request exceeds this limit, its request body will be ignored and it will
+ * be processed like a request with no request body at all. See below for
+ * explicit configuration to override this setting.
+ *
+ * By default, this class will try to avoid consuming more than half of your
+ * `memory_limit` for buffering multiple concurrent HTTP requests. As such, with
+ * the above default settings of `128M` max, it will try to consume no more than
+ * `64M` for buffering multiple concurrent HTTP requests. As a consequence, it
+ * will limit the concurrency to `1024` HTTP requests with the above defaults.
+ *
+ * It is imperative that you assign reasonable values to your PHP ini settings.
+ * It is usually recommended to not support buffering incoming HTTP requests
+ * with a large HTTP request body (e.g. large file uploads). If you want to
+ * increase this buffer size, you will have to also increase the total memory
+ * limit to allow for more concurrent requests (set `memory_limit 512M` or more)
+ * or explicitly limit concurrency.
+ *
+ * In order to override the above buffering defaults, you can configure the
+ * `HttpServer` explicitly. You can use the
+ * [`LimitConcurrentRequestsMiddleware`](#limitconcurrentrequestsmiddleware) and
+ * [`RequestBodyBufferMiddleware`](#requestbodybuffermiddleware) (see below)
+ * to explicitly configure the total number of requests that can be handled at
+ * once like this:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+ * new React\Http\Middleware\RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+ * new React\Http\Middleware\RequestBodyParserMiddleware(),
+ * $handler
+ * ));
+ * ```
+ *
+ * In this example, we allow processing up to 100 concurrent requests at once
+ * and each request can buffer up to `2M`. This means you may have to keep a
+ * maximum of `200M` of memory for incoming request body buffers. Accordingly,
+ * you need to adjust the `memory_limit` ini setting to allow for these buffers
+ * plus your actual application logic memory requirements (think `512M` or more).
+ *
+ * > Internally, this class automatically assigns these middleware handlers
+ * automatically when no [`StreamingRequestMiddleware`](#streamingrequestmiddleware)
+ * is given. Accordingly, you can use this example to override all default
+ * settings to implement custom limits.
+ *
+ * As an alternative to buffering the complete request body in memory, you can
+ * also use a streaming approach where only small chunks of data have to be kept
+ * in memory:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * $handler
+ * );
+ * ```
+ *
+ * In this case, it will invoke the request handler function once the HTTP
+ * request headers have been received, i.e. before receiving the potentially
+ * much larger HTTP request body. This means the [request](#server-request) passed to
+ * your request handler function may not be fully compatible with PSR-7. This is
+ * specifically designed to help with more advanced use cases where you want to
+ * have full control over consuming the incoming HTTP request body and
+ * concurrency settings. See also [streaming incoming request](#streaming-incoming-request)
+ * below for more details.
+ *
+ * > Changelog v1.5.0: This class has been renamed to `HttpServer` from the
+ * previous `Server` class in order to avoid any ambiguities.
+ * The previous name has been deprecated and should not be used anymore.
+ */
+final class HttpServer extends EventEmitter
+{
+ /**
+ * The maximum buffer size used for each request.
+ *
+ * This needs to be limited because the server can process a large number of
+ * requests concurrently, so the server may potentially consume a large
+ * amount of memory otherwise.
+ *
+ * See `RequestBodyBufferMiddleware` to override this setting.
+ *
+ * @internal
+ */
+ const MAXIMUM_BUFFER_SIZE = 65536; // 64 KiB
+
+ /**
+ * @var StreamingServer
+ */
+ private $streamingServer;
+
+ /**
+ * Creates an HTTP server that invokes the given callback for each incoming HTTP request
+ *
+ * In order to process any connections, the server needs to be attached to an
+ * instance of `React\Socket\ServerInterface` which emits underlying streaming
+ * connections in order to then parse incoming data as HTTP.
+ * See also [listen()](#listen) for more details.
+ *
+ * @param callable|LoopInterface $requestHandlerOrLoop
+ * @param callable[] ...$requestHandler
+ * @see self::listen()
+ */
+ public function __construct($requestHandlerOrLoop)
+ {
+ $requestHandlers = \func_get_args();
+ if (reset($requestHandlers) instanceof LoopInterface) {
+ $loop = \array_shift($requestHandlers);
+ } else {
+ $loop = Loop::get();
+ }
+
+ $requestHandlersCount = \count($requestHandlers);
+ if ($requestHandlersCount === 0 || \count(\array_filter($requestHandlers, 'is_callable')) < $requestHandlersCount) {
+ throw new \InvalidArgumentException('Invalid request handler given');
+ }
+
+ $streaming = false;
+ foreach ((array) $requestHandlers as $handler) {
+ if ($handler instanceof StreamingRequestMiddleware) {
+ $streaming = true;
+ break;
+ }
+ }
+
+ $middleware = array();
+ if (!$streaming) {
+ $maxSize = $this->getMaxRequestSize();
+ $concurrency = $this->getConcurrentRequestsLimit(\ini_get('memory_limit'), $maxSize);
+ if ($concurrency !== null) {
+ $middleware[] = new LimitConcurrentRequestsMiddleware($concurrency);
+ }
+ $middleware[] = new RequestBodyBufferMiddleware($maxSize);
+ // Checking for an empty string because that is what a boolean
+ // false is returned as by ini_get depending on the PHP version.
+ // @link http://php.net/manual/en/ini.core.php#ini.enable-post-data-reading
+ // @link http://php.net/manual/en/function.ini-get.php#refsect1-function.ini-get-notes
+ // @link https://3v4l.org/qJtsa
+ $enablePostDataReading = \ini_get('enable_post_data_reading');
+ if ($enablePostDataReading !== '') {
+ $middleware[] = new RequestBodyParserMiddleware();
+ }
+ }
+
+ $middleware = \array_merge($middleware, $requestHandlers);
+
+ /**
+ * Filter out any configuration middleware, no need to run requests through something that isn't
+ * doing anything with the request.
+ */
+ $middleware = \array_filter($middleware, function ($handler) {
+ return !($handler instanceof StreamingRequestMiddleware);
+ });
+
+ $this->streamingServer = new StreamingServer($loop, new MiddlewareRunner($middleware));
+
+ $that = $this;
+ $this->streamingServer->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error));
+ });
+ }
+
+ /**
+ * Starts listening for HTTP requests on the given socket server instance
+ *
+ * The given [`React\Socket\ServerInterface`](https://github.com/reactphp/socket#serverinterface)
+ * is responsible for emitting the underlying streaming connections. This
+ * HTTP server needs to be attached to it in order to process any
+ * connections and pase incoming streaming data as incoming HTTP request
+ * messages. In its most common form, you can attach this to a
+ * [`React\Socket\SocketServer`](https://github.com/reactphp/socket#socketserver)
+ * in order to start a plaintext HTTP server like this:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer($handler);
+ *
+ * $socket = new React\Socket\SocketServer('0.0.0.0:8080');
+ * $http->listen($socket);
+ * ```
+ *
+ * See also [hello world server example](../examples/51-server-hello-world.php)
+ * for more details.
+ *
+ * This example will start listening for HTTP requests on the alternative
+ * HTTP port `8080` on all interfaces (publicly). As an alternative, it is
+ * very common to use a reverse proxy and let this HTTP server listen on the
+ * localhost (loopback) interface only by using the listen address
+ * `127.0.0.1:8080` instead. This way, you host your application(s) on the
+ * default HTTP port `80` and only route specific requests to this HTTP
+ * server.
+ *
+ * Likewise, it's usually recommended to use a reverse proxy setup to accept
+ * secure HTTPS requests on default HTTPS port `443` (TLS termination) and
+ * only route plaintext requests to this HTTP server. As an alternative, you
+ * can also accept secure HTTPS requests with this HTTP server by attaching
+ * this to a [`React\Socket\SocketServer`](https://github.com/reactphp/socket#socketserver)
+ * using a secure TLS listen address, a certificate file and optional
+ * `passphrase` like this:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer($handler);
+ *
+ * $socket = new React\Socket\SocketServer('tls://0.0.0.0:8443', array(
+ * 'tls' => array(
+ * 'local_cert' => __DIR__ . '/localhost.pem'
+ * )
+ * ));
+ * $http->listen($socket);
+ * ```
+ *
+ * See also [hello world HTTPS example](../examples/61-server-hello-world-https.php)
+ * for more details.
+ *
+ * @param ServerInterface $socket
+ */
+ public function listen(ServerInterface $socket)
+ {
+ $this->streamingServer->listen($socket);
+ }
+
+ /**
+ * @param string $memory_limit
+ * @param string $post_max_size
+ * @return ?int
+ */
+ private function getConcurrentRequestsLimit($memory_limit, $post_max_size)
+ {
+ if ($memory_limit == -1) {
+ return null;
+ }
+
+ $availableMemory = IniUtil::iniSizeToBytes($memory_limit) / 2;
+ $concurrentRequests = (int) \ceil($availableMemory / IniUtil::iniSizeToBytes($post_max_size));
+
+ return $concurrentRequests;
+ }
+
+ /**
+ * @param ?string $post_max_size
+ * @return int
+ */
+ private function getMaxRequestSize($post_max_size = null)
+ {
+ $maxSize = IniUtil::iniSizeToBytes($post_max_size === null ? \ini_get('post_max_size') : $post_max_size);
+
+ return ($maxSize === 0 || $maxSize >= self::MAXIMUM_BUFFER_SIZE) ? self::MAXIMUM_BUFFER_SIZE : $maxSize;
+ }
+}
diff --git a/vendor/react/http/src/Io/BufferedBody.php b/vendor/react/http/src/Io/BufferedBody.php
new file mode 100644
index 0000000..4a4d839
--- /dev/null
+++ b/vendor/react/http/src/Io/BufferedBody.php
@@ -0,0 +1,179 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * [Internal] PSR-7 message body implementation using an in-memory buffer
+ *
+ * @internal
+ */
+class BufferedBody implements StreamInterface
+{
+ private $buffer = '';
+ private $position = 0;
+ private $closed = false;
+
+ /**
+ * @param string $buffer
+ */
+ public function __construct($buffer)
+ {
+ $this->buffer = $buffer;
+ }
+
+ public function __toString()
+ {
+ if ($this->closed) {
+ return '';
+ }
+
+ $this->seek(0);
+
+ return $this->getContents();
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ $this->position = 0;
+ $this->closed = true;
+ }
+
+ public function detach()
+ {
+ $this->close();
+
+ return null;
+ }
+
+ public function getSize()
+ {
+ return $this->closed ? null : \strlen($this->buffer);
+ }
+
+ public function tell()
+ {
+ if ($this->closed) {
+ throw new \RuntimeException('Unable to tell position of closed stream');
+ }
+
+ return $this->position;
+ }
+
+ public function eof()
+ {
+ return $this->position >= \strlen($this->buffer);
+ }
+
+ public function isSeekable()
+ {
+ return !$this->closed;
+ }
+
+ public function seek($offset, $whence = \SEEK_SET)
+ {
+ if ($this->closed) {
+ throw new \RuntimeException('Unable to seek on closed stream');
+ }
+
+ $old = $this->position;
+
+ if ($whence === \SEEK_SET) {
+ $this->position = $offset;
+ } elseif ($whence === \SEEK_CUR) {
+ $this->position += $offset;
+ } elseif ($whence === \SEEK_END) {
+ $this->position = \strlen($this->buffer) + $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid seek mode given');
+ }
+
+ if (!\is_int($this->position) || $this->position < 0) {
+ $this->position = $old;
+ throw new \RuntimeException('Unable to seek to position');
+ }
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function isWritable()
+ {
+ return !$this->closed;
+ }
+
+ public function write($string)
+ {
+ if ($this->closed) {
+ throw new \RuntimeException('Unable to write to closed stream');
+ }
+
+ if ($string === '') {
+ return 0;
+ }
+
+ if ($this->position > 0 && !isset($this->buffer[$this->position - 1])) {
+ $this->buffer = \str_pad($this->buffer, $this->position, "\0");
+ }
+
+ $len = \strlen($string);
+ $this->buffer = \substr($this->buffer, 0, $this->position) . $string . \substr($this->buffer, $this->position + $len);
+ $this->position += $len;
+
+ return $len;
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed;
+ }
+
+ public function read($length)
+ {
+ if ($this->closed) {
+ throw new \RuntimeException('Unable to read from closed stream');
+ }
+
+ if ($length < 1) {
+ throw new \InvalidArgumentException('Invalid read length given');
+ }
+
+ if ($this->position + $length > \strlen($this->buffer)) {
+ $length = \strlen($this->buffer) - $this->position;
+ }
+
+ if (!isset($this->buffer[$this->position])) {
+ return '';
+ }
+
+ $pos = $this->position;
+ $this->position += $length;
+
+ return \substr($this->buffer, $pos, $length);
+ }
+
+ public function getContents()
+ {
+ if ($this->closed) {
+ throw new \RuntimeException('Unable to read from closed stream');
+ }
+
+ if (!isset($this->buffer[$this->position])) {
+ return '';
+ }
+
+ $pos = $this->position;
+ $this->position = \strlen($this->buffer);
+
+ return \substr($this->buffer, $pos);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key === null ? array() : null;
+ }
+}
diff --git a/vendor/react/http/src/Io/ChunkedDecoder.php b/vendor/react/http/src/Io/ChunkedDecoder.php
new file mode 100644
index 0000000..2f58f42
--- /dev/null
+++ b/vendor/react/http/src/Io/ChunkedDecoder.php
@@ -0,0 +1,175 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+use Exception;
+
+/**
+ * [Internal] Decodes "Transfer-Encoding: chunked" from given stream and returns only payload data.
+ *
+ * This is used internally to decode incoming requests with this encoding.
+ *
+ * @internal
+ */
+class ChunkedDecoder extends EventEmitter implements ReadableStreamInterface
+{
+ const CRLF = "\r\n";
+ const MAX_CHUNK_HEADER_SIZE = 1024;
+
+ private $closed = false;
+ private $input;
+ private $buffer = '';
+ private $chunkSize = 0;
+ private $transferredSize = 0;
+ private $headerCompleted = false;
+
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->buffer = '';
+
+ $this->closed = true;
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if (!$this->closed) {
+ $this->handleError(new Exception('Unexpected end event'));
+ }
+ }
+
+ /** @internal */
+ public function handleError(Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->buffer .= $data;
+
+ while ($this->buffer !== '') {
+ if (!$this->headerCompleted) {
+ $positionCrlf = \strpos($this->buffer, static::CRLF);
+
+ if ($positionCrlf === false) {
+ // Header shouldn't be bigger than 1024 bytes
+ if (isset($this->buffer[static::MAX_CHUNK_HEADER_SIZE])) {
+ $this->handleError(new Exception('Chunk header size inclusive extension bigger than' . static::MAX_CHUNK_HEADER_SIZE. ' bytes'));
+ }
+ return;
+ }
+
+ $header = \strtolower((string)\substr($this->buffer, 0, $positionCrlf));
+ $hexValue = $header;
+
+ if (\strpos($header, ';') !== false) {
+ $array = \explode(';', $header);
+ $hexValue = $array[0];
+ }
+
+ if ($hexValue !== '') {
+ $hexValue = \ltrim(\trim($hexValue), "0");
+ if ($hexValue === '') {
+ $hexValue = "0";
+ }
+ }
+
+ $this->chunkSize = @\hexdec($hexValue);
+ if (!\is_int($this->chunkSize) || \dechex($this->chunkSize) !== $hexValue) {
+ $this->handleError(new Exception($hexValue . ' is not a valid hexadecimal number'));
+ return;
+ }
+
+ $this->buffer = (string)\substr($this->buffer, $positionCrlf + 2);
+ $this->headerCompleted = true;
+ if ($this->buffer === '') {
+ return;
+ }
+ }
+
+ $chunk = (string)\substr($this->buffer, 0, $this->chunkSize - $this->transferredSize);
+
+ if ($chunk !== '') {
+ $this->transferredSize += \strlen($chunk);
+ $this->emit('data', array($chunk));
+ $this->buffer = (string)\substr($this->buffer, \strlen($chunk));
+ }
+
+ $positionCrlf = \strpos($this->buffer, static::CRLF);
+
+ if ($positionCrlf === 0) {
+ if ($this->chunkSize === 0) {
+ $this->emit('end');
+ $this->close();
+ return;
+ }
+ $this->chunkSize = 0;
+ $this->headerCompleted = false;
+ $this->transferredSize = 0;
+ $this->buffer = (string)\substr($this->buffer, 2);
+ } elseif ($this->chunkSize === 0) {
+ // end chunk received, skip all trailer data
+ $this->buffer = (string)\substr($this->buffer, $positionCrlf);
+ }
+
+ if ($positionCrlf !== 0 && $this->chunkSize !== 0 && $this->chunkSize === $this->transferredSize && \strlen($this->buffer) > 2) {
+ // the first 2 characters are not CRLF, send error event
+ $this->handleError(new Exception('Chunk does not end with a CRLF'));
+ return;
+ }
+
+ if ($positionCrlf !== 0 && \strlen($this->buffer) < 2) {
+ // No CRLF found, wait for additional data which could be a CRLF
+ return;
+ }
+ }
+ }
+}
diff --git a/vendor/react/http/src/Io/ChunkedEncoder.php b/vendor/react/http/src/Io/ChunkedEncoder.php
new file mode 100644
index 0000000..c84ef54
--- /dev/null
+++ b/vendor/react/http/src/Io/ChunkedEncoder.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Encodes given payload stream with "Transfer-Encoding: chunked" and emits encoded data
+ *
+ * This is used internally to encode outgoing requests with this encoding.
+ *
+ * @internal
+ */
+class ChunkedEncoder extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ if ($data !== '') {
+ $this->emit('data', array(
+ \dechex(\strlen($data)) . "\r\n" . $data . "\r\n"
+ ));
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->emit('data', array("0\r\n\r\n"));
+
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+}
diff --git a/vendor/react/http/src/Io/CloseProtectionStream.php b/vendor/react/http/src/Io/CloseProtectionStream.php
new file mode 100644
index 0000000..2e1ed6e
--- /dev/null
+++ b/vendor/react/http/src/Io/CloseProtectionStream.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Protects a given stream from actually closing and only discards its incoming data instead.
+ *
+ * This is used internally to prevent the underlying connection from closing, so
+ * that we can still send back a response over the same stream.
+ *
+ * @internal
+ * */
+class CloseProtectionStream extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $closed = false;
+ private $paused = false;
+
+ /**
+ * @param ReadableStreamInterface $input stream that will be discarded instead of closing it on an 'close' event.
+ */
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->paused = true;
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->paused = false;
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ // stop listening for incoming events
+ $this->input->removeListener('data', array($this, 'handleData'));
+ $this->input->removeListener('error', array($this, 'handleError'));
+ $this->input->removeListener('end', array($this, 'handleEnd'));
+ $this->input->removeListener('close', array($this, 'close'));
+
+ // resume the stream to ensure we discard everything from incoming connection
+ if ($this->paused) {
+ $this->paused = false;
+ $this->input->resume();
+ }
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->emit('data', array($data));
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ $this->emit('end');
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ }
+}
diff --git a/vendor/react/http/src/Io/EmptyBodyStream.php b/vendor/react/http/src/Io/EmptyBodyStream.php
new file mode 100644
index 0000000..5056219
--- /dev/null
+++ b/vendor/react/http/src/Io/EmptyBodyStream.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\StreamInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Bridge between an empty StreamInterface from PSR-7 and ReadableStreamInterface from ReactPHP
+ *
+ * This class is used in the server to represent an empty body stream of an
+ * incoming response from the client. This is similar to the `HttpBodyStream`,
+ * but is specifically designed for the common case of having an empty message
+ * body.
+ *
+ * Note that this is an internal class only and nothing you should usually care
+ * about. See the `StreamInterface` and `ReadableStreamInterface` for more
+ * details.
+ *
+ * @see HttpBodyStream
+ * @see StreamInterface
+ * @see ReadableStreamInterface
+ * @internal
+ */
+class EmptyBodyStream extends EventEmitter implements StreamInterface, ReadableStreamInterface
+{
+ private $closed = false;
+
+ public function isReadable()
+ {
+ return !$this->closed;
+ }
+
+ public function pause()
+ {
+ // NOOP
+ }
+
+ public function resume()
+ {
+ // NOOP
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ public function getSize()
+ {
+ return 0;
+ }
+
+ /** @ignore */
+ public function __toString()
+ {
+ return '';
+ }
+
+ /** @ignore */
+ public function detach()
+ {
+ return null;
+ }
+
+ /** @ignore */
+ public function tell()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function eof()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ /** @ignore */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function rewind()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /** @ignore */
+ public function write($string)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function read($length)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function getContents()
+ {
+ return '';
+ }
+
+ /** @ignore */
+ public function getMetadata($key = null)
+ {
+ return ($key === null) ? array() : null;
+ }
+}
diff --git a/vendor/react/http/src/Io/HttpBodyStream.php b/vendor/react/http/src/Io/HttpBodyStream.php
new file mode 100644
index 0000000..25d15a1
--- /dev/null
+++ b/vendor/react/http/src/Io/HttpBodyStream.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\StreamInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Bridge between StreamInterface from PSR-7 and ReadableStreamInterface from ReactPHP
+ *
+ * This class is used in the server to stream the body of an incoming response
+ * from the client. This allows us to stream big amounts of data without having
+ * to buffer this data. Similarly, this used to stream the body of an outgoing
+ * request body to the client. The data will be sent directly to the client.
+ *
+ * Note that this is an internal class only and nothing you should usually care
+ * about. See the `StreamInterface` and `ReadableStreamInterface` for more
+ * details.
+ *
+ * @see StreamInterface
+ * @see ReadableStreamInterface
+ * @internal
+ */
+class HttpBodyStream extends EventEmitter implements StreamInterface, ReadableStreamInterface
+{
+ public $input;
+ private $closed = false;
+ private $size;
+
+ /**
+ * @param ReadableStreamInterface $input Stream data from $stream as a body of a PSR-7 object4
+ * @param int|null $size size of the data body
+ */
+ public function __construct(ReadableStreamInterface $input, $size)
+ {
+ $this->input = $input;
+ $this->size = $size;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /** @ignore */
+ public function __toString()
+ {
+ return '';
+ }
+
+ /** @ignore */
+ public function detach()
+ {
+ return null;
+ }
+
+ /** @ignore */
+ public function tell()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function eof()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ /** @ignore */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function rewind()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /** @ignore */
+ public function write($string)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function read($length)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ /** @ignore */
+ public function getContents()
+ {
+ return '';
+ }
+
+ /** @ignore */
+ public function getMetadata($key = null)
+ {
+ return null;
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ $this->emit('data', array($data));
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+}
diff --git a/vendor/react/http/src/Io/IniUtil.php b/vendor/react/http/src/Io/IniUtil.php
new file mode 100644
index 0000000..612aae2
--- /dev/null
+++ b/vendor/react/http/src/Io/IniUtil.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace React\Http\Io;
+
+/**
+ * @internal
+ */
+final class IniUtil
+{
+ /**
+ * Convert a ini like size to a numeric size in bytes.
+ *
+ * @param string $size
+ * @return int
+ */
+ public static function iniSizeToBytes($size)
+ {
+ if (\is_numeric($size)) {
+ return (int)$size;
+ }
+
+ $suffix = \strtoupper(\substr($size, -1));
+ $strippedSize = \substr($size, 0, -1);
+
+ if (!\is_numeric($strippedSize)) {
+ throw new \InvalidArgumentException("$size is not a valid ini size");
+ }
+
+ if ($strippedSize <= 0) {
+ throw new \InvalidArgumentException("Expect $size to be higher isn't zero or lower");
+ }
+
+ if ($suffix === 'K') {
+ return $strippedSize * 1024;
+ }
+ if ($suffix === 'M') {
+ return $strippedSize * 1024 * 1024;
+ }
+ if ($suffix === 'G') {
+ return $strippedSize * 1024 * 1024 * 1024;
+ }
+ if ($suffix === 'T') {
+ return $strippedSize * 1024 * 1024 * 1024 * 1024;
+ }
+
+ return (int)$size;
+ }
+}
diff --git a/vendor/react/http/src/Io/LengthLimitedStream.php b/vendor/react/http/src/Io/LengthLimitedStream.php
new file mode 100644
index 0000000..bc64c54
--- /dev/null
+++ b/vendor/react/http/src/Io/LengthLimitedStream.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Limits the amount of data the given stream can emit
+ *
+ * This is used internally to limit the size of the underlying connection stream
+ * to the size defined by the "Content-Length" header of the incoming request.
+ *
+ * @internal
+ */
+class LengthLimitedStream extends EventEmitter implements ReadableStreamInterface
+{
+ private $stream;
+ private $closed = false;
+ private $transferredLength = 0;
+ private $maxLength;
+
+ public function __construct(ReadableStreamInterface $stream, $maxLength)
+ {
+ $this->stream = $stream;
+ $this->maxLength = $maxLength;
+
+ $this->stream->on('data', array($this, 'handleData'));
+ $this->stream->on('end', array($this, 'handleEnd'));
+ $this->stream->on('error', array($this, 'handleError'));
+ $this->stream->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed && $this->stream->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->stream->pause();
+ }
+
+ public function resume()
+ {
+ $this->stream->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ $this->stream->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ if (($this->transferredLength + \strlen($data)) > $this->maxLength) {
+ // Only emit data until the value of 'Content-Length' is reached, the rest will be ignored
+ $data = (string)\substr($data, 0, $this->maxLength - $this->transferredLength);
+ }
+
+ if ($data !== '') {
+ $this->transferredLength += \strlen($data);
+ $this->emit('data', array($data));
+ }
+
+ if ($this->transferredLength === $this->maxLength) {
+ // 'Content-Length' reached, stream will end
+ $this->emit('end');
+ $this->close();
+ $this->stream->removeListener('data', array($this, 'handleData'));
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if (!$this->closed) {
+ $this->handleError(new \Exception('Unexpected end event'));
+ }
+ }
+
+}
diff --git a/vendor/react/http/src/Io/MiddlewareRunner.php b/vendor/react/http/src/Io/MiddlewareRunner.php
new file mode 100644
index 0000000..dedf6ff
--- /dev/null
+++ b/vendor/react/http/src/Io/MiddlewareRunner.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use React\Promise\PromiseInterface;
+
+/**
+ * [Internal] Middleware runner to expose an array of middleware request handlers as a single request handler callable
+ *
+ * @internal
+ */
+final class MiddlewareRunner
+{
+ /**
+ * @var callable[]
+ */
+ private $middleware;
+
+ /**
+ * @param callable[] $middleware
+ */
+ public function __construct(array $middleware)
+ {
+ $this->middleware = \array_values($middleware);
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @return ResponseInterface|PromiseInterface<ResponseInterface>
+ * @throws \Exception
+ */
+ public function __invoke(ServerRequestInterface $request)
+ {
+ if (empty($this->middleware)) {
+ throw new \RuntimeException('No middleware to run');
+ }
+
+ return $this->call($request, 0);
+ }
+
+ /** @internal */
+ public function call(ServerRequestInterface $request, $position)
+ {
+ // final request handler will be invoked without a next handler
+ if (!isset($this->middleware[$position + 1])) {
+ $handler = $this->middleware[$position];
+ return $handler($request);
+ }
+
+ $that = $this;
+ $next = function (ServerRequestInterface $request) use ($that, $position) {
+ return $that->call($request, $position + 1);
+ };
+
+ // invoke middleware request handler with next handler
+ $handler = $this->middleware[$position];
+ return $handler($request, $next);
+ }
+}
diff --git a/vendor/react/http/src/Io/MultipartParser.php b/vendor/react/http/src/Io/MultipartParser.php
new file mode 100644
index 0000000..536694f
--- /dev/null
+++ b/vendor/react/http/src/Io/MultipartParser.php
@@ -0,0 +1,328 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * [Internal] Parses a string body with "Content-Type: multipart/form-data" into structured data
+ *
+ * This is use internally to parse incoming request bodies into structured data
+ * that resembles PHP's `$_POST` and `$_FILES` superglobals.
+ *
+ * @internal
+ * @link https://tools.ietf.org/html/rfc7578
+ * @link https://tools.ietf.org/html/rfc2046#section-5.1.1
+ */
+final class MultipartParser
+{
+ /**
+ * @var ServerRequestInterface|null
+ */
+ private $request;
+
+ /**
+ * @var int|null
+ */
+ private $maxFileSize;
+
+ /**
+ * ini setting "max_input_vars"
+ *
+ * Does not exist in PHP < 5.3.9 or HHVM, so assume PHP's default 1000 here.
+ *
+ * @var int
+ * @link http://php.net/manual/en/info.configuration.php#ini.max-input-vars
+ */
+ private $maxInputVars = 1000;
+
+ /**
+ * ini setting "max_input_nesting_level"
+ *
+ * Does not exist in HHVM, but assumes hard coded to 64 (PHP's default).
+ *
+ * @var int
+ * @link http://php.net/manual/en/info.configuration.php#ini.max-input-nesting-level
+ */
+ private $maxInputNestingLevel = 64;
+
+ /**
+ * ini setting "upload_max_filesize"
+ *
+ * @var int
+ */
+ private $uploadMaxFilesize;
+
+ /**
+ * ini setting "max_file_uploads"
+ *
+ * Additionally, setting "file_uploads = off" effectively sets this to zero.
+ *
+ * @var int
+ */
+ private $maxFileUploads;
+
+ private $postCount = 0;
+ private $filesCount = 0;
+ private $emptyCount = 0;
+
+ /**
+ * @param int|string|null $uploadMaxFilesize
+ * @param int|null $maxFileUploads
+ */
+ public function __construct($uploadMaxFilesize = null, $maxFileUploads = null)
+ {
+ $var = \ini_get('max_input_vars');
+ if ($var !== false) {
+ $this->maxInputVars = (int)$var;
+ }
+ $var = \ini_get('max_input_nesting_level');
+ if ($var !== false) {
+ $this->maxInputNestingLevel = (int)$var;
+ }
+
+ if ($uploadMaxFilesize === null) {
+ $uploadMaxFilesize = \ini_get('upload_max_filesize');
+ }
+
+ $this->uploadMaxFilesize = IniUtil::iniSizeToBytes($uploadMaxFilesize);
+ $this->maxFileUploads = $maxFileUploads === null ? (\ini_get('file_uploads') === '' ? 0 : (int)\ini_get('max_file_uploads')) : (int)$maxFileUploads;
+ }
+
+ public function parse(ServerRequestInterface $request)
+ {
+ $contentType = $request->getHeaderLine('content-type');
+ if(!\preg_match('/boundary="?(.*?)"?$/', $contentType, $matches)) {
+ return $request;
+ }
+
+ $this->request = $request;
+ $this->parseBody('--' . $matches[1], (string)$request->getBody());
+
+ $request = $this->request;
+ $this->request = null;
+ $this->postCount = 0;
+ $this->filesCount = 0;
+ $this->emptyCount = 0;
+ $this->maxFileSize = null;
+
+ return $request;
+ }
+
+ private function parseBody($boundary, $buffer)
+ {
+ $len = \strlen($boundary);
+
+ // ignore everything before initial boundary (SHOULD be empty)
+ $start = \strpos($buffer, $boundary . "\r\n");
+
+ while ($start !== false) {
+ // search following boundary (preceded by newline)
+ // ignore last if not followed by boundary (SHOULD end with "--")
+ $start += $len + 2;
+ $end = \strpos($buffer, "\r\n" . $boundary, $start);
+ if ($end === false) {
+ break;
+ }
+
+ // parse one part and continue searching for next
+ $this->parsePart(\substr($buffer, $start, $end - $start));
+ $start = $end;
+ }
+ }
+
+ private function parsePart($chunk)
+ {
+ $pos = \strpos($chunk, "\r\n\r\n");
+ if ($pos === false) {
+ return;
+ }
+
+ $headers = $this->parseHeaders((string)substr($chunk, 0, $pos));
+ $body = (string)\substr($chunk, $pos + 4);
+
+ if (!isset($headers['content-disposition'])) {
+ return;
+ }
+
+ $name = $this->getParameterFromHeader($headers['content-disposition'], 'name');
+ if ($name === null) {
+ return;
+ }
+
+ $filename = $this->getParameterFromHeader($headers['content-disposition'], 'filename');
+ if ($filename !== null) {
+ $this->parseFile(
+ $name,
+ $filename,
+ isset($headers['content-type'][0]) ? $headers['content-type'][0] : null,
+ $body
+ );
+ } else {
+ $this->parsePost($name, $body);
+ }
+ }
+
+ private function parseFile($name, $filename, $contentType, $contents)
+ {
+ $file = $this->parseUploadedFile($filename, $contentType, $contents);
+ if ($file === null) {
+ return;
+ }
+
+ $this->request = $this->request->withUploadedFiles($this->extractPost(
+ $this->request->getUploadedFiles(),
+ $name,
+ $file
+ ));
+ }
+
+ private function parseUploadedFile($filename, $contentType, $contents)
+ {
+ $size = \strlen($contents);
+
+ // no file selected (zero size and empty filename)
+ if ($size === 0 && $filename === '') {
+ // ignore excessive number of empty file uploads
+ if (++$this->emptyCount + $this->filesCount > $this->maxInputVars) {
+ return;
+ }
+
+ return new UploadedFile(
+ new BufferedBody(''),
+ $size,
+ \UPLOAD_ERR_NO_FILE,
+ $filename,
+ $contentType
+ );
+ }
+
+ // ignore excessive number of file uploads
+ if (++$this->filesCount > $this->maxFileUploads) {
+ return;
+ }
+
+ // file exceeds "upload_max_filesize" ini setting
+ if ($size > $this->uploadMaxFilesize) {
+ return new UploadedFile(
+ new BufferedBody(''),
+ $size,
+ \UPLOAD_ERR_INI_SIZE,
+ $filename,
+ $contentType
+ );
+ }
+
+ // file exceeds MAX_FILE_SIZE value
+ if ($this->maxFileSize !== null && $size > $this->maxFileSize) {
+ return new UploadedFile(
+ new BufferedBody(''),
+ $size,
+ \UPLOAD_ERR_FORM_SIZE,
+ $filename,
+ $contentType
+ );
+ }
+
+ return new UploadedFile(
+ new BufferedBody($contents),
+ $size,
+ \UPLOAD_ERR_OK,
+ $filename,
+ $contentType
+ );
+ }
+
+ private function parsePost($name, $value)
+ {
+ // ignore excessive number of post fields
+ if (++$this->postCount > $this->maxInputVars) {
+ return;
+ }
+
+ $this->request = $this->request->withParsedBody($this->extractPost(
+ $this->request->getParsedBody(),
+ $name,
+ $value
+ ));
+
+ if (\strtoupper($name) === 'MAX_FILE_SIZE') {
+ $this->maxFileSize = (int)$value;
+
+ if ($this->maxFileSize === 0) {
+ $this->maxFileSize = null;
+ }
+ }
+ }
+
+ private function parseHeaders($header)
+ {
+ $headers = array();
+
+ foreach (\explode("\r\n", \trim($header)) as $line) {
+ $parts = \explode(':', $line, 2);
+ if (!isset($parts[1])) {
+ continue;
+ }
+
+ $key = \strtolower(trim($parts[0]));
+ $values = \explode(';', $parts[1]);
+ $values = \array_map('trim', $values);
+ $headers[$key] = $values;
+ }
+
+ return $headers;
+ }
+
+ private function getParameterFromHeader(array $header, $parameter)
+ {
+ foreach ($header as $part) {
+ if (\preg_match('/' . $parameter . '="?(.*?)"?$/', $part, $matches)) {
+ return $matches[1];
+ }
+ }
+
+ return null;
+ }
+
+ private function extractPost($postFields, $key, $value)
+ {
+ $chunks = \explode('[', $key);
+ if (\count($chunks) == 1) {
+ $postFields[$key] = $value;
+ return $postFields;
+ }
+
+ // ignore this key if maximum nesting level is exceeded
+ if (isset($chunks[$this->maxInputNestingLevel])) {
+ return $postFields;
+ }
+
+ $chunkKey = \rtrim($chunks[0], ']');
+ $parent = &$postFields;
+ for ($i = 1; isset($chunks[$i]); $i++) {
+ $previousChunkKey = $chunkKey;
+
+ if ($previousChunkKey === '') {
+ $parent[] = array();
+ \end($parent);
+ $parent = &$parent[\key($parent)];
+ } else {
+ if (!isset($parent[$previousChunkKey]) || !\is_array($parent[$previousChunkKey])) {
+ $parent[$previousChunkKey] = array();
+ }
+ $parent = &$parent[$previousChunkKey];
+ }
+
+ $chunkKey = \rtrim($chunks[$i], ']');
+ }
+
+ if ($chunkKey === '') {
+ $parent[] = $value;
+ } else {
+ $parent[$chunkKey] = $value;
+ }
+
+ return $postFields;
+ }
+}
diff --git a/vendor/react/http/src/Io/PauseBufferStream.php b/vendor/react/http/src/Io/PauseBufferStream.php
new file mode 100644
index 0000000..fb5ed45
--- /dev/null
+++ b/vendor/react/http/src/Io/PauseBufferStream.php
@@ -0,0 +1,188 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * [Internal] Pauses a given stream and buffers all events while paused
+ *
+ * This class is used to buffer all events that happen on a given stream while
+ * it is paused. This allows you to pause a stream and no longer watch for any
+ * of its events. Once the stream is resumed, all buffered events will be
+ * emitted. Explicitly closing the resulting stream clears all buffers.
+ *
+ * Note that this is an internal class only and nothing you should usually care
+ * about.
+ *
+ * @see ReadableStreamInterface
+ * @internal
+ */
+class PauseBufferStream extends EventEmitter implements ReadableStreamInterface
+{
+ private $input;
+ private $closed = false;
+ private $paused = false;
+ private $dataPaused = '';
+ private $endPaused = false;
+ private $closePaused = false;
+ private $errorPaused;
+ private $implicit = false;
+
+ public function __construct(ReadableStreamInterface $input)
+ {
+ $this->input = $input;
+
+ $this->input->on('data', array($this, 'handleData'));
+ $this->input->on('end', array($this, 'handleEnd'));
+ $this->input->on('error', array($this, 'handleError'));
+ $this->input->on('close', array($this, 'handleClose'));
+ }
+
+ /**
+ * pause and remember this was not explicitly from user control
+ *
+ * @internal
+ */
+ public function pauseImplicit()
+ {
+ $this->pause();
+ $this->implicit = true;
+ }
+
+ /**
+ * resume only if this was previously paused implicitly and not explicitly from user control
+ *
+ * @internal
+ */
+ public function resumeImplicit()
+ {
+ if ($this->implicit) {
+ $this->resume();
+ }
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed;
+ }
+
+ public function pause()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->input->pause();
+ $this->paused = true;
+ $this->implicit = false;
+ }
+
+ public function resume()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->paused = false;
+ $this->implicit = false;
+
+ if ($this->dataPaused !== '') {
+ $this->emit('data', array($this->dataPaused));
+ $this->dataPaused = '';
+ }
+
+ if ($this->errorPaused) {
+ $this->emit('error', array($this->errorPaused));
+ return $this->close();
+ }
+
+ if ($this->endPaused) {
+ $this->endPaused = false;
+ $this->emit('end');
+ return $this->close();
+ }
+
+ if ($this->closePaused) {
+ $this->closePaused = false;
+ return $this->close();
+ }
+
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->dataPaused = '';
+ $this->endPaused = $this->closePaused = false;
+ $this->errorPaused = null;
+
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleData($data)
+ {
+ if ($this->paused) {
+ $this->dataPaused .= $data;
+ return;
+ }
+
+ $this->emit('data', array($data));
+ }
+
+ /** @internal */
+ public function handleError(\Exception $e)
+ {
+ if ($this->paused) {
+ $this->errorPaused = $e;
+ return;
+ }
+
+ $this->emit('error', array($e));
+ $this->close();
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if ($this->paused) {
+ $this->endPaused = true;
+ return;
+ }
+
+ if (!$this->closed) {
+ $this->emit('end');
+ $this->close();
+ }
+ }
+
+ /** @internal */
+ public function handleClose()
+ {
+ if ($this->paused) {
+ $this->closePaused = true;
+ return;
+ }
+
+ $this->close();
+ }
+}
diff --git a/vendor/react/http/src/Io/ReadableBodyStream.php b/vendor/react/http/src/Io/ReadableBodyStream.php
new file mode 100644
index 0000000..daef45f
--- /dev/null
+++ b/vendor/react/http/src/Io/ReadableBodyStream.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\StreamInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @internal
+ */
+class ReadableBodyStream extends EventEmitter implements ReadableStreamInterface, StreamInterface
+{
+ private $input;
+ private $position = 0;
+ private $size;
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $input, $size = null)
+ {
+ $this->input = $input;
+ $this->size = $size;
+
+ $that = $this;
+ $pos =& $this->position;
+ $input->on('data', function ($data) use ($that, &$pos, $size) {
+ $that->emit('data', array($data));
+
+ $pos += \strlen($data);
+ if ($size !== null && $pos >= $size) {
+ $that->handleEnd();
+ }
+ });
+ $input->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error));
+ $that->close();
+ });
+ $input->on('end', array($that, 'handleEnd'));
+ $input->on('close', array($that, 'close'));
+ }
+
+ public function close()
+ {
+ if (!$this->closed) {
+ $this->closed = true;
+ $this->input->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+ }
+
+ public function isReadable()
+ {
+ return $this->input->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function eof()
+ {
+ return !$this->isReadable();
+ }
+
+ public function __toString()
+ {
+ return '';
+ }
+
+ public function detach()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function rewind()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function read($length)
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getContents()
+ {
+ throw new \BadMethodCallException();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return ($key === null) ? array() : null;
+ }
+
+ /** @internal */
+ public function handleEnd()
+ {
+ if ($this->position !== $this->size && $this->size !== null) {
+ $this->emit('error', array(new \UnderflowException('Unexpected end of response body after ' . $this->position . '/' . $this->size . ' bytes')));
+ } else {
+ $this->emit('end');
+ }
+
+ $this->close();
+ }
+}
diff --git a/vendor/react/http/src/Io/RequestHeaderParser.php b/vendor/react/http/src/Io/RequestHeaderParser.php
new file mode 100644
index 0000000..e5554c4
--- /dev/null
+++ b/vendor/react/http/src/Io/RequestHeaderParser.php
@@ -0,0 +1,281 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\ServerRequestInterface;
+use React\Http\Message\Response;
+use React\Http\Message\ServerRequest;
+use React\Socket\ConnectionInterface;
+use Exception;
+
+/**
+ * [Internal] Parses an incoming request header from an input stream
+ *
+ * This is used internally to parse the request header from the connection and
+ * then process the remaining connection as the request body.
+ *
+ * @event headers
+ * @event error
+ *
+ * @internal
+ */
+class RequestHeaderParser extends EventEmitter
+{
+ private $maxSize = 8192;
+
+ public function handle(ConnectionInterface $conn)
+ {
+ $buffer = '';
+ $maxSize = $this->maxSize;
+ $that = $this;
+ $conn->on('data', $fn = function ($data) use (&$buffer, &$fn, $conn, $maxSize, $that) {
+ // append chunk of data to buffer and look for end of request headers
+ $buffer .= $data;
+ $endOfHeader = \strpos($buffer, "\r\n\r\n");
+
+ // reject request if buffer size is exceeded
+ if ($endOfHeader > $maxSize || ($endOfHeader === false && isset($buffer[$maxSize]))) {
+ $conn->removeListener('data', $fn);
+ $fn = null;
+
+ $that->emit('error', array(
+ new \OverflowException("Maximum header size of {$maxSize} exceeded.", Response::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE),
+ $conn
+ ));
+ return;
+ }
+
+ // ignore incomplete requests
+ if ($endOfHeader === false) {
+ return;
+ }
+
+ // request headers received => try to parse request
+ $conn->removeListener('data', $fn);
+ $fn = null;
+
+ try {
+ $request = $that->parseRequest(
+ (string)\substr($buffer, 0, $endOfHeader + 2),
+ $conn->getRemoteAddress(),
+ $conn->getLocalAddress()
+ );
+ } catch (Exception $exception) {
+ $buffer = '';
+ $that->emit('error', array(
+ $exception,
+ $conn
+ ));
+ return;
+ }
+
+ $contentLength = 0;
+ if ($request->hasHeader('Transfer-Encoding')) {
+ $contentLength = null;
+ } elseif ($request->hasHeader('Content-Length')) {
+ $contentLength = (int)$request->getHeaderLine('Content-Length');
+ }
+
+ if ($contentLength === 0) {
+ // happy path: request body is known to be empty
+ $stream = new EmptyBodyStream();
+ $request = $request->withBody($stream);
+ } else {
+ // otherwise body is present => delimit using Content-Length or ChunkedDecoder
+ $stream = new CloseProtectionStream($conn);
+ if ($contentLength !== null) {
+ $stream = new LengthLimitedStream($stream, $contentLength);
+ } else {
+ $stream = new ChunkedDecoder($stream);
+ }
+
+ $request = $request->withBody(new HttpBodyStream($stream, $contentLength));
+ }
+
+ $bodyBuffer = isset($buffer[$endOfHeader + 4]) ? \substr($buffer, $endOfHeader + 4) : '';
+ $buffer = '';
+ $that->emit('headers', array($request, $conn));
+
+ if ($bodyBuffer !== '') {
+ $conn->emit('data', array($bodyBuffer));
+ }
+
+ // happy path: request body is known to be empty => immediately end stream
+ if ($contentLength === 0) {
+ $stream->emit('end');
+ $stream->close();
+ }
+ });
+ }
+
+ /**
+ * @param string $headers buffer string containing request headers only
+ * @param ?string $remoteSocketUri
+ * @param ?string $localSocketUri
+ * @return ServerRequestInterface
+ * @throws \InvalidArgumentException
+ * @internal
+ */
+ public function parseRequest($headers, $remoteSocketUri, $localSocketUri)
+ {
+ // additional, stricter safe-guard for request line
+ // because request parser doesn't properly cope with invalid ones
+ $start = array();
+ if (!\preg_match('#^(?<method>[^ ]+) (?<target>[^ ]+) HTTP/(?<version>\d\.\d)#m', $headers, $start)) {
+ throw new \InvalidArgumentException('Unable to parse invalid request-line');
+ }
+
+ // only support HTTP/1.1 and HTTP/1.0 requests
+ if ($start['version'] !== '1.1' && $start['version'] !== '1.0') {
+ throw new \InvalidArgumentException('Received request with invalid protocol version', Response::STATUS_VERSION_NOT_SUPPORTED);
+ }
+
+ // match all request header fields into array, thanks to @kelunik for checking the HTTP specs and coming up with this regex
+ $matches = array();
+ $n = \preg_match_all('/^([^()<>@,;:\\\"\/\[\]?={}\x01-\x20\x7F]++):[\x20\x09]*+((?:[\x20\x09]*+[\x21-\x7E\x80-\xFF]++)*+)[\x20\x09]*+[\r]?+\n/m', $headers, $matches, \PREG_SET_ORDER);
+
+ // check number of valid header fields matches number of lines + request line
+ if (\substr_count($headers, "\n") !== $n + 1) {
+ throw new \InvalidArgumentException('Unable to parse invalid request header fields');
+ }
+
+ // format all header fields into associative array
+ $host = null;
+ $fields = array();
+ foreach ($matches as $match) {
+ $fields[$match[1]][] = $match[2];
+
+ // match `Host` request header
+ if ($host === null && \strtolower($match[1]) === 'host') {
+ $host = $match[2];
+ }
+ }
+
+ // create new obj implementing ServerRequestInterface by preserving all
+ // previous properties and restoring original request-target
+ $serverParams = array(
+ 'REQUEST_TIME' => \time(),
+ 'REQUEST_TIME_FLOAT' => \microtime(true)
+ );
+
+ // scheme is `http` unless TLS is used
+ $localParts = $localSocketUri === null ? array() : \parse_url($localSocketUri);
+ if (isset($localParts['scheme']) && $localParts['scheme'] === 'tls') {
+ $scheme = 'https://';
+ $serverParams['HTTPS'] = 'on';
+ } else {
+ $scheme = 'http://';
+ }
+
+ // default host if unset comes from local socket address or defaults to localhost
+ $hasHost = $host !== null;
+ if ($host === null) {
+ $host = isset($localParts['host'], $localParts['port']) ? $localParts['host'] . ':' . $localParts['port'] : '127.0.0.1';
+ }
+
+ if ($start['method'] === 'OPTIONS' && $start['target'] === '*') {
+ // support asterisk-form for `OPTIONS *` request line only
+ $uri = $scheme . $host;
+ } elseif ($start['method'] === 'CONNECT') {
+ $parts = \parse_url('tcp://' . $start['target']);
+
+ // check this is a valid authority-form request-target (host:port)
+ if (!isset($parts['scheme'], $parts['host'], $parts['port']) || \count($parts) !== 3) {
+ throw new \InvalidArgumentException('CONNECT method MUST use authority-form request target');
+ }
+ $uri = $scheme . $start['target'];
+ } else {
+ // support absolute-form or origin-form for proxy requests
+ if ($start['target'][0] === '/') {
+ $uri = $scheme . $host . $start['target'];
+ } else {
+ // ensure absolute-form request-target contains a valid URI
+ $parts = \parse_url($start['target']);
+
+ // make sure value contains valid host component (IP or hostname), but no fragment
+ if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'http' || isset($parts['fragment'])) {
+ throw new \InvalidArgumentException('Invalid absolute-form request-target');
+ }
+
+ $uri = $start['target'];
+ }
+ }
+
+ // apply REMOTE_ADDR and REMOTE_PORT if source address is known
+ // address should always be known, unless this is over Unix domain sockets (UDS)
+ if ($remoteSocketUri !== null) {
+ $remoteAddress = \parse_url($remoteSocketUri);
+ $serverParams['REMOTE_ADDR'] = $remoteAddress['host'];
+ $serverParams['REMOTE_PORT'] = $remoteAddress['port'];
+ }
+
+ // apply SERVER_ADDR and SERVER_PORT if server address is known
+ // address should always be known, even for Unix domain sockets (UDS)
+ // but skip UDS as it doesn't have a concept of host/port.
+ if ($localSocketUri !== null && isset($localParts['host'], $localParts['port'])) {
+ $serverParams['SERVER_ADDR'] = $localParts['host'];
+ $serverParams['SERVER_PORT'] = $localParts['port'];
+ }
+
+ $request = new ServerRequest(
+ $start['method'],
+ $uri,
+ $fields,
+ '',
+ $start['version'],
+ $serverParams
+ );
+
+ // only assign request target if it is not in origin-form (happy path for most normal requests)
+ if ($start['target'][0] !== '/') {
+ $request = $request->withRequestTarget($start['target']);
+ }
+
+ if ($hasHost) {
+ // Optional Host request header value MUST be valid (host and optional port)
+ $parts = \parse_url('http://' . $request->getHeaderLine('Host'));
+
+ // make sure value contains valid host component (IP or hostname)
+ if (!$parts || !isset($parts['scheme'], $parts['host'])) {
+ $parts = false;
+ }
+
+ // make sure value does not contain any other URI component
+ if (\is_array($parts)) {
+ unset($parts['scheme'], $parts['host'], $parts['port']);
+ }
+ if ($parts === false || $parts) {
+ throw new \InvalidArgumentException('Invalid Host header value');
+ }
+ } elseif (!$hasHost && $start['version'] === '1.1' && $start['method'] !== 'CONNECT') {
+ // require Host request header for HTTP/1.1 (except for CONNECT method)
+ throw new \InvalidArgumentException('Missing required Host request header');
+ } elseif (!$hasHost) {
+ // remove default Host request header for HTTP/1.0 when not explicitly given
+ $request = $request->withoutHeader('Host');
+ }
+
+ // ensure message boundaries are valid according to Content-Length and Transfer-Encoding request headers
+ if ($request->hasHeader('Transfer-Encoding')) {
+ if (\strtolower($request->getHeaderLine('Transfer-Encoding')) !== 'chunked') {
+ throw new \InvalidArgumentException('Only chunked-encoding is allowed for Transfer-Encoding', Response::STATUS_NOT_IMPLEMENTED);
+ }
+
+ // Transfer-Encoding: chunked and Content-Length header MUST NOT be used at the same time
+ // as per https://tools.ietf.org/html/rfc7230#section-3.3.3
+ if ($request->hasHeader('Content-Length')) {
+ throw new \InvalidArgumentException('Using both `Transfer-Encoding: chunked` and `Content-Length` is not allowed', Response::STATUS_BAD_REQUEST);
+ }
+ } elseif ($request->hasHeader('Content-Length')) {
+ $string = $request->getHeaderLine('Content-Length');
+
+ if ((string)(int)$string !== $string) {
+ // Content-Length value is not an integer or not a single integer
+ throw new \InvalidArgumentException('The value of `Content-Length` is not valid', Response::STATUS_BAD_REQUEST);
+ }
+ }
+
+ return $request;
+ }
+}
diff --git a/vendor/react/http/src/Io/Sender.php b/vendor/react/http/src/Io/Sender.php
new file mode 100644
index 0000000..2f04c79
--- /dev/null
+++ b/vendor/react/http/src/Io/Sender.php
@@ -0,0 +1,160 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use React\EventLoop\LoopInterface;
+use React\Http\Client\Client as HttpClient;
+use React\Http\Message\Response;
+use React\Promise\PromiseInterface;
+use React\Promise\Deferred;
+use React\Socket\ConnectorInterface;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * [Internal] Sends requests and receives responses
+ *
+ * The `Sender` is responsible for passing the [`RequestInterface`](#requestinterface) objects to
+ * the underlying [`HttpClient`](https://github.com/reactphp/http-client) library
+ * and keeps track of its transmission and converts its reponses back to [`ResponseInterface`](#responseinterface) objects.
+ *
+ * It also registers everything with the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
+ * and the default [`Connector`](https://github.com/reactphp/socket-client) and [DNS `Resolver`](https://github.com/reactphp/dns).
+ *
+ * The `Sender` class mostly exists in order to abstract changes on the underlying
+ * components away from this package in order to provide backwards and forwards
+ * compatibility.
+ *
+ * @internal You SHOULD NOT rely on this API, it is subject to change without prior notice!
+ * @see Browser
+ */
+class Sender
+{
+ /**
+ * create a new default sender attached to the given event loop
+ *
+ * This method is used internally to create the "default sender".
+ *
+ * You may also use this method if you need custom DNS or connector
+ * settings. You can use this method manually like this:
+ *
+ * ```php
+ * $connector = new \React\Socket\Connector(array(), $loop);
+ * $sender = \React\Http\Io\Sender::createFromLoop($loop, $connector);
+ * ```
+ *
+ * @param LoopInterface $loop
+ * @param ConnectorInterface|null $connector
+ * @return self
+ */
+ public static function createFromLoop(LoopInterface $loop, ConnectorInterface $connector = null)
+ {
+ return new self(new HttpClient($loop, $connector));
+ }
+
+ private $http;
+
+ /**
+ * [internal] Instantiate Sender
+ *
+ * @param HttpClient $http
+ * @internal
+ */
+ public function __construct(HttpClient $http)
+ {
+ $this->http = $http;
+ }
+
+ /**
+ *
+ * @internal
+ * @param RequestInterface $request
+ * @return PromiseInterface Promise<ResponseInterface, Exception>
+ */
+ public function send(RequestInterface $request)
+ {
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ if ($size !== null && $size !== 0) {
+ // automatically assign a "Content-Length" request header if the body size is known and non-empty
+ $request = $request->withHeader('Content-Length', (string)$size);
+ } elseif ($size === 0 && \in_array($request->getMethod(), array('POST', 'PUT', 'PATCH'))) {
+ // only assign a "Content-Length: 0" request header if the body is expected for certain methods
+ $request = $request->withHeader('Content-Length', '0');
+ } elseif ($body instanceof ReadableStreamInterface && $body->isReadable() && !$request->hasHeader('Content-Length')) {
+ // use "Transfer-Encoding: chunked" when this is a streaming body and body size is unknown
+ $request = $request->withHeader('Transfer-Encoding', 'chunked');
+ } else {
+ // do not use chunked encoding if size is known or if this is an empty request body
+ $size = 0;
+ }
+
+ $headers = array();
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers[$name] = implode(', ', $values);
+ }
+
+ $requestStream = $this->http->request($request->getMethod(), (string)$request->getUri(), $headers, $request->getProtocolVersion());
+
+ $deferred = new Deferred(function ($_, $reject) use ($requestStream) {
+ // close request stream if request is cancelled
+ $reject(new \RuntimeException('Request cancelled'));
+ $requestStream->close();
+ });
+
+ $requestStream->on('error', function($error) use ($deferred) {
+ $deferred->reject($error);
+ });
+
+ $requestStream->on('response', function (ResponseInterface $response, ReadableStreamInterface $body) use ($deferred, $request) {
+ $length = null;
+ $code = $response->getStatusCode();
+ if ($request->getMethod() === 'HEAD' || ($code >= 100 && $code < 200) || $code == Response::STATUS_NO_CONTENT || $code == Response::STATUS_NOT_MODIFIED) {
+ $length = 0;
+ } elseif (\strtolower($response->getHeaderLine('Transfer-Encoding')) === 'chunked') {
+ $body = new ChunkedDecoder($body);
+ } elseif ($response->hasHeader('Content-Length')) {
+ $length = (int) $response->getHeaderLine('Content-Length');
+ }
+
+ $deferred->resolve($response->withBody(new ReadableBodyStream($body, $length)));
+ });
+
+ if ($body instanceof ReadableStreamInterface) {
+ if ($body->isReadable()) {
+ // length unknown => apply chunked transfer-encoding
+ if ($size === null) {
+ $body = new ChunkedEncoder($body);
+ }
+
+ // pipe body into request stream
+ // add dummy write to immediately start request even if body does not emit any data yet
+ $body->pipe($requestStream);
+ $requestStream->write('');
+
+ $body->on('close', $close = function () use ($deferred, $requestStream) {
+ $deferred->reject(new \RuntimeException('Request failed because request body closed unexpectedly'));
+ $requestStream->close();
+ });
+ $body->on('error', function ($e) use ($deferred, $requestStream, $close, $body) {
+ $body->removeListener('close', $close);
+ $deferred->reject(new \RuntimeException('Request failed because request body reported an error', 0, $e));
+ $requestStream->close();
+ });
+ $body->on('end', function () use ($close, $body) {
+ $body->removeListener('close', $close);
+ });
+ } else {
+ // stream is not readable => end request without body
+ $requestStream->end();
+ }
+ } else {
+ // body is fully buffered => write as one chunk
+ $requestStream->end((string)$body);
+ }
+
+ return $deferred->promise();
+ }
+}
diff --git a/vendor/react/http/src/Io/StreamingServer.php b/vendor/react/http/src/Io/StreamingServer.php
new file mode 100644
index 0000000..7818f0b
--- /dev/null
+++ b/vendor/react/http/src/Io/StreamingServer.php
@@ -0,0 +1,383 @@
+<?php
+
+namespace React\Http\Io;
+
+use Evenement\EventEmitter;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use React\EventLoop\LoopInterface;
+use React\Http\Message\Response;
+use React\Http\Message\ServerRequest;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\PromiseInterface;
+use React\Socket\ConnectionInterface;
+use React\Socket\ServerInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * The internal `StreamingServer` class is responsible for handling incoming connections and then
+ * processing each incoming HTTP request.
+ *
+ * Unlike the [`HttpServer`](#httpserver) class, it does not buffer and parse the incoming
+ * HTTP request body by default. This means that the request handler will be
+ * invoked with a streaming request body. Once the request headers have been
+ * received, it will invoke the request handler function. This request handler
+ * function needs to be passed to the constructor and will be invoked with the
+ * respective [request](#request) object and expects a [response](#response)
+ * object in return:
+ *
+ * ```php
+ * $server = new StreamingServer($loop, function (ServerRequestInterface $request) {
+ * return new Response(
+ * Response::STATUS_OK,
+ * array(
+ * 'Content-Type' => 'text/plain'
+ * ),
+ * "Hello World!\n"
+ * );
+ * });
+ * ```
+ *
+ * Each incoming HTTP request message is always represented by the
+ * [PSR-7 `ServerRequestInterface`](https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface),
+ * see also following [request](#request) chapter for more details.
+ * Each outgoing HTTP response message is always represented by the
+ * [PSR-7 `ResponseInterface`](https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface),
+ * see also following [response](#response) chapter for more details.
+ *
+ * In order to process any connections, the server needs to be attached to an
+ * instance of `React\Socket\ServerInterface` through the [`listen()`](#listen) method
+ * as described in the following chapter. In its most simple form, you can attach
+ * this to a [`React\Socket\SocketServer`](https://github.com/reactphp/socket#socketserver)
+ * in order to start a plaintext HTTP server like this:
+ *
+ * ```php
+ * $server = new StreamingServer($loop, $handler);
+ *
+ * $socket = new React\Socket\SocketServer('0.0.0.0:8080', array(), $loop);
+ * $server->listen($socket);
+ * ```
+ *
+ * See also the [`listen()`](#listen) method and the [first example](examples) for more details.
+ *
+ * The `StreamingServer` class is considered advanced usage and unless you know
+ * what you're doing, you're recommended to use the [`HttpServer`](#httpserver) class
+ * instead. The `StreamingServer` class is specifically designed to help with
+ * more advanced use cases where you want to have full control over consuming
+ * the incoming HTTP request body and concurrency settings.
+ *
+ * In particular, this class does not buffer and parse the incoming HTTP request
+ * in memory. It will invoke the request handler function once the HTTP request
+ * headers have been received, i.e. before receiving the potentially much larger
+ * HTTP request body. This means the [request](#request) passed to your request
+ * handler function may not be fully compatible with PSR-7. See also
+ * [streaming request](#streaming-request) below for more details.
+ *
+ * @see \React\Http\HttpServer
+ * @see \React\Http\Message\Response
+ * @see self::listen()
+ * @internal
+ */
+final class StreamingServer extends EventEmitter
+{
+ private $callback;
+ private $parser;
+ private $loop;
+
+ /**
+ * Creates an HTTP server that invokes the given callback for each incoming HTTP request
+ *
+ * In order to process any connections, the server needs to be attached to an
+ * instance of `React\Socket\ServerInterface` which emits underlying streaming
+ * connections in order to then parse incoming data as HTTP.
+ * See also [listen()](#listen) for more details.
+ *
+ * @param LoopInterface $loop
+ * @param callable $requestHandler
+ * @see self::listen()
+ */
+ public function __construct(LoopInterface $loop, $requestHandler)
+ {
+ if (!\is_callable($requestHandler)) {
+ throw new \InvalidArgumentException('Invalid request handler given');
+ }
+
+ $this->loop = $loop;
+
+ $this->callback = $requestHandler;
+ $this->parser = new RequestHeaderParser();
+
+ $that = $this;
+ $this->parser->on('headers', function (ServerRequestInterface $request, ConnectionInterface $conn) use ($that) {
+ $that->handleRequest($conn, $request);
+ });
+
+ $this->parser->on('error', function(\Exception $e, ConnectionInterface $conn) use ($that) {
+ $that->emit('error', array($e));
+
+ // parsing failed => assume dummy request and send appropriate error
+ $that->writeError(
+ $conn,
+ $e->getCode() !== 0 ? $e->getCode() : Response::STATUS_BAD_REQUEST,
+ new ServerRequest('GET', '/')
+ );
+ });
+ }
+
+ /**
+ * Starts listening for HTTP requests on the given socket server instance
+ *
+ * @param ServerInterface $socket
+ * @see \React\Http\HttpServer::listen()
+ */
+ public function listen(ServerInterface $socket)
+ {
+ $socket->on('connection', array($this->parser, 'handle'));
+ }
+
+ /** @internal */
+ public function handleRequest(ConnectionInterface $conn, ServerRequestInterface $request)
+ {
+ if ($request->getProtocolVersion() !== '1.0' && '100-continue' === \strtolower($request->getHeaderLine('Expect'))) {
+ $conn->write("HTTP/1.1 100 Continue\r\n\r\n");
+ }
+
+ // execute request handler callback
+ $callback = $this->callback;
+ try {
+ $response = $callback($request);
+ } catch (\Exception $error) {
+ // request handler callback throws an Exception
+ $response = Promise\reject($error);
+ } catch (\Throwable $error) { // @codeCoverageIgnoreStart
+ // request handler callback throws a PHP7+ Error
+ $response = Promise\reject($error); // @codeCoverageIgnoreEnd
+ }
+
+ // cancel pending promise once connection closes
+ if ($response instanceof CancellablePromiseInterface) {
+ $conn->on('close', function () use ($response) {
+ $response->cancel();
+ });
+ }
+
+ // happy path: response returned, handle and return immediately
+ if ($response instanceof ResponseInterface) {
+ return $this->handleResponse($conn, $request, $response);
+ }
+
+ // did not return a promise? this is an error, convert into one for rejection below.
+ if (!$response instanceof PromiseInterface) {
+ $response = Promise\resolve($response);
+ }
+
+ $that = $this;
+ $response->then(
+ function ($response) use ($that, $conn, $request) {
+ if (!$response instanceof ResponseInterface) {
+ $message = 'The response callback is expected to resolve with an object implementing Psr\Http\Message\ResponseInterface, but resolved with "%s" instead.';
+ $message = \sprintf($message, \is_object($response) ? \get_class($response) : \gettype($response));
+ $exception = new \RuntimeException($message);
+
+ $that->emit('error', array($exception));
+ return $that->writeError($conn, Response::STATUS_INTERNAL_SERVER_ERROR, $request);
+ }
+ $that->handleResponse($conn, $request, $response);
+ },
+ function ($error) use ($that, $conn, $request) {
+ $message = 'The response callback is expected to resolve with an object implementing Psr\Http\Message\ResponseInterface, but rejected with "%s" instead.';
+ $message = \sprintf($message, \is_object($error) ? \get_class($error) : \gettype($error));
+
+ $previous = null;
+
+ if ($error instanceof \Throwable || $error instanceof \Exception) {
+ $previous = $error;
+ }
+
+ $exception = new \RuntimeException($message, 0, $previous);
+
+ $that->emit('error', array($exception));
+ return $that->writeError($conn, Response::STATUS_INTERNAL_SERVER_ERROR, $request);
+ }
+ );
+ }
+
+ /** @internal */
+ public function writeError(ConnectionInterface $conn, $code, ServerRequestInterface $request)
+ {
+ $response = new Response(
+ $code,
+ array(
+ 'Content-Type' => 'text/plain',
+ 'Connection' => 'close' // we do not want to keep the connection open after an error
+ ),
+ 'Error ' . $code
+ );
+
+ // append reason phrase to response body if known
+ $reason = $response->getReasonPhrase();
+ if ($reason !== '') {
+ $body = $response->getBody();
+ $body->seek(0, SEEK_END);
+ $body->write(': ' . $reason);
+ }
+
+ $this->handleResponse($conn, $request, $response);
+ }
+
+
+ /** @internal */
+ public function handleResponse(ConnectionInterface $connection, ServerRequestInterface $request, ResponseInterface $response)
+ {
+ // return early and close response body if connection is already closed
+ $body = $response->getBody();
+ if (!$connection->isWritable()) {
+ $body->close();
+ return;
+ }
+
+ $code = $response->getStatusCode();
+ $method = $request->getMethod();
+
+ // assign HTTP protocol version from request automatically
+ $version = $request->getProtocolVersion();
+ $response = $response->withProtocolVersion($version);
+
+ // assign default "Server" header automatically
+ if (!$response->hasHeader('Server')) {
+ $response = $response->withHeader('Server', 'ReactPHP/1');
+ } elseif ($response->getHeaderLine('Server') === ''){
+ $response = $response->withoutHeader('Server');
+ }
+
+ // assign default "Date" header from current time automatically
+ if (!$response->hasHeader('Date')) {
+ // IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
+ $response = $response->withHeader('Date', gmdate('D, d M Y H:i:s') . ' GMT');
+ } elseif ($response->getHeaderLine('Date') === ''){
+ $response = $response->withoutHeader('Date');
+ }
+
+ // assign "Content-Length" header automatically
+ $chunked = false;
+ if (($method === 'CONNECT' && $code >= 200 && $code < 300) || ($code >= 100 && $code < 200) || $code === Response::STATUS_NO_CONTENT) {
+ // 2xx response to CONNECT and 1xx and 204 MUST NOT include Content-Length or Transfer-Encoding header
+ $response = $response->withoutHeader('Content-Length');
+ } elseif ($code === Response::STATUS_NOT_MODIFIED && ($response->hasHeader('Content-Length') || $body->getSize() === 0)) {
+ // 304 Not Modified: preserve explicit Content-Length and preserve missing header if body is empty
+ } elseif ($body->getSize() !== null) {
+ // assign Content-Length header when using a "normal" buffered body string
+ $response = $response->withHeader('Content-Length', (string)$body->getSize());
+ } elseif (!$response->hasHeader('Content-Length') && $version === '1.1') {
+ // assign chunked transfer-encoding if no 'content-length' is given for HTTP/1.1 responses
+ $chunked = true;
+ }
+
+ // assign "Transfer-Encoding" header automatically
+ if ($chunked) {
+ $response = $response->withHeader('Transfer-Encoding', 'chunked');
+ } else {
+ // remove any Transfer-Encoding headers unless automatically enabled above
+ $response = $response->withoutHeader('Transfer-Encoding');
+ }
+
+ // assign "Connection" header automatically
+ $persist = false;
+ if ($code === Response::STATUS_SWITCHING_PROTOCOLS) {
+ // 101 (Switching Protocols) response uses Connection: upgrade header
+ // This implies that this stream now uses another protocol and we
+ // may not persist this connection for additional requests.
+ $response = $response->withHeader('Connection', 'upgrade');
+ } elseif (\strtolower($request->getHeaderLine('Connection')) === 'close' || \strtolower($response->getHeaderLine('Connection')) === 'close') {
+ // obey explicit "Connection: close" request header or response header if present
+ $response = $response->withHeader('Connection', 'close');
+ } elseif ($version === '1.1') {
+ // HTTP/1.1 assumes persistent connection support by default, so we don't need to inform client
+ $persist = true;
+ } elseif (strtolower($request->getHeaderLine('Connection')) === 'keep-alive') {
+ // obey explicit "Connection: keep-alive" request header and inform client
+ $persist = true;
+ $response = $response->withHeader('Connection', 'keep-alive');
+ } else {
+ // remove any Connection headers unless automatically enabled above
+ $response = $response->withoutHeader('Connection');
+ }
+
+ // 101 (Switching Protocols) response (for Upgrade request) forwards upgraded data through duplex stream
+ // 2xx (Successful) response to CONNECT forwards tunneled application data through duplex stream
+ if (($code === Response::STATUS_SWITCHING_PROTOCOLS || ($method === 'CONNECT' && $code >= 200 && $code < 300)) && $body instanceof HttpBodyStream && $body->input instanceof WritableStreamInterface) {
+ if ($request->getBody()->isReadable()) {
+ // request is still streaming => wait for request close before forwarding following data from connection
+ $request->getBody()->on('close', function () use ($connection, $body) {
+ if ($body->input->isWritable()) {
+ $connection->pipe($body->input);
+ $connection->resume();
+ }
+ });
+ } elseif ($body->input->isWritable()) {
+ // request already closed => forward following data from connection
+ $connection->pipe($body->input);
+ $connection->resume();
+ }
+ }
+
+ // build HTTP response header by appending status line and header fields
+ $headers = "HTTP/" . $version . " " . $code . " " . $response->getReasonPhrase() . "\r\n";
+ foreach ($response->getHeaders() as $name => $values) {
+ foreach ($values as $value) {
+ $headers .= $name . ": " . $value . "\r\n";
+ }
+ }
+
+ // response to HEAD and 1xx, 204 and 304 responses MUST NOT include a body
+ // exclude status 101 (Switching Protocols) here for Upgrade request handling above
+ if ($method === 'HEAD' || ($code >= 100 && $code < 200 && $code !== Response::STATUS_SWITCHING_PROTOCOLS) || $code === Response::STATUS_NO_CONTENT || $code === Response::STATUS_NOT_MODIFIED) {
+ $body->close();
+ $body = '';
+ }
+
+ // this is a non-streaming response body or the body stream already closed?
+ if (!$body instanceof ReadableStreamInterface || !$body->isReadable()) {
+ // add final chunk if a streaming body is already closed and uses `Transfer-Encoding: chunked`
+ if ($body instanceof ReadableStreamInterface && $chunked) {
+ $body = "0\r\n\r\n";
+ }
+
+ // write response headers and body
+ $connection->write($headers . "\r\n" . $body);
+
+ // either wait for next request over persistent connection or end connection
+ if ($persist) {
+ $this->parser->handle($connection);
+ } else {
+ $connection->end();
+ }
+ return;
+ }
+
+ $connection->write($headers . "\r\n");
+
+ if ($chunked) {
+ $body = new ChunkedEncoder($body);
+ }
+
+ // Close response stream once connection closes.
+ // Note that this TCP/IP close detection may take some time,
+ // in particular this may only fire on a later read/write attempt.
+ $connection->on('close', array($body, 'close'));
+
+ // write streaming body and then wait for next request over persistent connection
+ if ($persist) {
+ $body->pipe($connection, array('end' => false));
+ $parser = $this->parser;
+ $body->on('end', function () use ($connection, $parser, $body) {
+ $connection->removeListener('close', array($body, 'close'));
+ $parser->handle($connection);
+ });
+ } else {
+ $body->pipe($connection);
+ }
+ }
+}
diff --git a/vendor/react/http/src/Io/Transaction.php b/vendor/react/http/src/Io/Transaction.php
new file mode 100644
index 0000000..7bf7008
--- /dev/null
+++ b/vendor/react/http/src/Io/Transaction.php
@@ -0,0 +1,303 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+use RingCentral\Psr7\Request;
+use RingCentral\Psr7\Uri;
+use React\EventLoop\LoopInterface;
+use React\Http\Message\ResponseException;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * @internal
+ */
+class Transaction
+{
+ private $sender;
+ private $loop;
+
+ // context: http.timeout (ini_get('default_socket_timeout'): 60)
+ private $timeout;
+
+ // context: http.follow_location (true)
+ private $followRedirects = true;
+
+ // context: http.max_redirects (10)
+ private $maxRedirects = 10;
+
+ // context: http.ignore_errors (false)
+ private $obeySuccessCode = true;
+
+ private $streaming = false;
+
+ private $maximumSize = 16777216; // 16 MiB = 2^24 bytes
+
+ public function __construct(Sender $sender, LoopInterface $loop)
+ {
+ $this->sender = $sender;
+ $this->loop = $loop;
+ }
+
+ /**
+ * @param array $options
+ * @return self returns new instance, without modifying existing instance
+ */
+ public function withOptions(array $options)
+ {
+ $transaction = clone $this;
+ foreach ($options as $name => $value) {
+ if (property_exists($transaction, $name)) {
+ // restore default value if null is given
+ if ($value === null) {
+ $default = new self($this->sender, $this->loop);
+ $value = $default->$name;
+ }
+
+ $transaction->$name = $value;
+ }
+ }
+
+ return $transaction;
+ }
+
+ public function send(RequestInterface $request)
+ {
+ $deferred = new Deferred(function () use (&$deferred) {
+ if (isset($deferred->pending)) {
+ $deferred->pending->cancel();
+ unset($deferred->pending);
+ }
+ });
+
+ $deferred->numRequests = 0;
+
+ // use timeout from options or default to PHP's default_socket_timeout (60)
+ $timeout = (float)($this->timeout !== null ? $this->timeout : ini_get("default_socket_timeout"));
+
+ $loop = $this->loop;
+ $this->next($request, $deferred)->then(
+ function (ResponseInterface $response) use ($deferred, $loop, &$timeout) {
+ if (isset($deferred->timeout)) {
+ $loop->cancelTimer($deferred->timeout);
+ unset($deferred->timeout);
+ }
+ $timeout = -1;
+ $deferred->resolve($response);
+ },
+ function ($e) use ($deferred, $loop, &$timeout) {
+ if (isset($deferred->timeout)) {
+ $loop->cancelTimer($deferred->timeout);
+ unset($deferred->timeout);
+ }
+ $timeout = -1;
+ $deferred->reject($e);
+ }
+ );
+
+ if ($timeout < 0) {
+ return $deferred->promise();
+ }
+
+ $body = $request->getBody();
+ if ($body instanceof ReadableStreamInterface && $body->isReadable()) {
+ $that = $this;
+ $body->on('close', function () use ($that, $deferred, &$timeout) {
+ if ($timeout >= 0) {
+ $that->applyTimeout($deferred, $timeout);
+ }
+ });
+ } else {
+ $this->applyTimeout($deferred, $timeout);
+ }
+
+ return $deferred->promise();
+ }
+
+ /**
+ * @internal
+ * @param Deferred $deferred
+ * @param number $timeout
+ * @return void
+ */
+ public function applyTimeout(Deferred $deferred, $timeout)
+ {
+ $deferred->timeout = $this->loop->addTimer($timeout, function () use ($timeout, $deferred) {
+ $deferred->reject(new \RuntimeException(
+ 'Request timed out after ' . $timeout . ' seconds'
+ ));
+ if (isset($deferred->pending)) {
+ $deferred->pending->cancel();
+ unset($deferred->pending);
+ }
+ });
+ }
+
+ private function next(RequestInterface $request, Deferred $deferred)
+ {
+ $this->progress('request', array($request));
+
+ $that = $this;
+ ++$deferred->numRequests;
+
+ $promise = $this->sender->send($request);
+
+ if (!$this->streaming) {
+ $promise = $promise->then(function ($response) use ($deferred, $that) {
+ return $that->bufferResponse($response, $deferred);
+ });
+ }
+
+ $deferred->pending = $promise;
+
+ return $promise->then(
+ function (ResponseInterface $response) use ($request, $that, $deferred) {
+ return $that->onResponse($response, $request, $deferred);
+ }
+ );
+ }
+
+ /**
+ * @internal
+ * @param ResponseInterface $response
+ * @return PromiseInterface Promise<ResponseInterface, Exception>
+ */
+ public function bufferResponse(ResponseInterface $response, $deferred)
+ {
+ $stream = $response->getBody();
+
+ $size = $stream->getSize();
+ if ($size !== null && $size > $this->maximumSize) {
+ $stream->close();
+ return \React\Promise\reject(new \OverflowException(
+ 'Response body size of ' . $size . ' bytes exceeds maximum of ' . $this->maximumSize . ' bytes',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 0
+ ));
+ }
+
+ // body is not streaming => already buffered
+ if (!$stream instanceof ReadableStreamInterface) {
+ return \React\Promise\resolve($response);
+ }
+
+ // buffer stream and resolve with buffered body
+ $maximumSize = $this->maximumSize;
+ $promise = \React\Promise\Stream\buffer($stream, $maximumSize)->then(
+ function ($body) use ($response) {
+ return $response->withBody(new BufferedBody($body));
+ },
+ function ($e) use ($stream, $maximumSize) {
+ // try to close stream if buffering fails (or is cancelled)
+ $stream->close();
+
+ if ($e instanceof \OverflowException) {
+ $e = new \OverflowException(
+ 'Response body size exceeds maximum of ' . $maximumSize . ' bytes',
+ \defined('SOCKET_EMSGSIZE') ? \SOCKET_EMSGSIZE : 0
+ );
+ }
+
+ throw $e;
+ }
+ );
+
+ $deferred->pending = $promise;
+
+ return $promise;
+ }
+
+ /**
+ * @internal
+ * @param ResponseInterface $response
+ * @param RequestInterface $request
+ * @throws ResponseException
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function onResponse(ResponseInterface $response, RequestInterface $request, $deferred)
+ {
+ $this->progress('response', array($response, $request));
+
+ // follow 3xx (Redirection) response status codes if Location header is present and not explicitly disabled
+ // @link https://tools.ietf.org/html/rfc7231#section-6.4
+ if ($this->followRedirects && ($response->getStatusCode() >= 300 && $response->getStatusCode() < 400) && $response->hasHeader('Location')) {
+ return $this->onResponseRedirect($response, $request, $deferred);
+ }
+
+ // only status codes 200-399 are considered to be valid, reject otherwise
+ if ($this->obeySuccessCode && ($response->getStatusCode() < 200 || $response->getStatusCode() >= 400)) {
+ throw new ResponseException($response);
+ }
+
+ // resolve our initial promise
+ return $response;
+ }
+
+ /**
+ * @param ResponseInterface $response
+ * @param RequestInterface $request
+ * @return PromiseInterface
+ * @throws \RuntimeException
+ */
+ private function onResponseRedirect(ResponseInterface $response, RequestInterface $request, Deferred $deferred)
+ {
+ // resolve location relative to last request URI
+ $location = Uri::resolve($request->getUri(), $response->getHeaderLine('Location'));
+
+ $request = $this->makeRedirectRequest($request, $location);
+ $this->progress('redirect', array($request));
+
+ if ($deferred->numRequests >= $this->maxRedirects) {
+ throw new \RuntimeException('Maximum number of redirects (' . $this->maxRedirects . ') exceeded');
+ }
+
+ return $this->next($request, $deferred);
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param UriInterface $location
+ * @return RequestInterface
+ */
+ private function makeRedirectRequest(RequestInterface $request, UriInterface $location)
+ {
+ $originalHost = $request->getUri()->getHost();
+ $request = $request
+ ->withoutHeader('Host')
+ ->withoutHeader('Content-Type')
+ ->withoutHeader('Content-Length');
+
+ // Remove authorization if changing hostnames (but not if just changing ports or protocols).
+ if ($location->getHost() !== $originalHost) {
+ $request = $request->withoutHeader('Authorization');
+ }
+
+ // naïve approach..
+ $method = ($request->getMethod() === 'HEAD') ? 'HEAD' : 'GET';
+
+ return new Request($method, $location, $request->getHeaders());
+ }
+
+ private function progress($name, array $args = array())
+ {
+ return;
+
+ echo $name;
+
+ foreach ($args as $arg) {
+ echo ' ';
+ if ($arg instanceof ResponseInterface) {
+ echo 'HTTP/' . $arg->getProtocolVersion() . ' ' . $arg->getStatusCode() . ' ' . $arg->getReasonPhrase();
+ } elseif ($arg instanceof RequestInterface) {
+ echo $arg->getMethod() . ' ' . $arg->getRequestTarget() . ' HTTP/' . $arg->getProtocolVersion();
+ } else {
+ echo $arg;
+ }
+ }
+
+ echo PHP_EOL;
+ }
+}
diff --git a/vendor/react/http/src/Io/UploadedFile.php b/vendor/react/http/src/Io/UploadedFile.php
new file mode 100644
index 0000000..f2a6c9e
--- /dev/null
+++ b/vendor/react/http/src/Io/UploadedFile.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace React\Http\Io;
+
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use InvalidArgumentException;
+use RuntimeException;
+
+/**
+ * [Internal] Implementation of the PSR-7 `UploadedFileInterface`
+ *
+ * This is used internally to represent each incoming file upload.
+ *
+ * Note that this is an internal class only and nothing you should usually care
+ * about. See the `UploadedFileInterface` for more details.
+ *
+ * @see UploadedFileInterface
+ * @internal
+ */
+final class UploadedFile implements UploadedFileInterface
+{
+ /**
+ * @var StreamInterface
+ */
+ private $stream;
+
+ /**
+ * @var int
+ */
+ private $size;
+
+ /**
+ * @var int
+ */
+ private $error;
+
+ /**
+ * @var string
+ */
+ private $filename;
+
+ /**
+ * @var string
+ */
+ private $mediaType;
+
+ /**
+ * @param StreamInterface $stream
+ * @param int $size
+ * @param int $error
+ * @param string $filename
+ * @param string $mediaType
+ */
+ public function __construct(StreamInterface $stream, $size, $error, $filename, $mediaType)
+ {
+ $this->stream = $stream;
+ $this->size = $size;
+
+ if (!\is_int($error) || !\in_array($error, array(
+ \UPLOAD_ERR_OK,
+ \UPLOAD_ERR_INI_SIZE,
+ \UPLOAD_ERR_FORM_SIZE,
+ \UPLOAD_ERR_PARTIAL,
+ \UPLOAD_ERR_NO_FILE,
+ \UPLOAD_ERR_NO_TMP_DIR,
+ \UPLOAD_ERR_CANT_WRITE,
+ \UPLOAD_ERR_EXTENSION,
+ ))) {
+ throw new InvalidArgumentException(
+ 'Invalid error code, must be an UPLOAD_ERR_* constant'
+ );
+ }
+ $this->error = $error;
+ $this->filename = $filename;
+ $this->mediaType = $mediaType;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStream()
+ {
+ if ($this->error !== \UPLOAD_ERR_OK) {
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
+ }
+
+ return $this->stream;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function moveTo($targetPath)
+ {
+ throw new RuntimeException('Not implemented');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientFilename()
+ {
+ return $this->filename;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientMediaType()
+ {
+ return $this->mediaType;
+ }
+}
diff --git a/vendor/react/http/src/Message/Response.php b/vendor/react/http/src/Message/Response.php
new file mode 100644
index 0000000..edd6245
--- /dev/null
+++ b/vendor/react/http/src/Message/Response.php
@@ -0,0 +1,291 @@
+<?php
+
+namespace React\Http\Message;
+
+use Fig\Http\Message\StatusCodeInterface;
+use Psr\Http\Message\StreamInterface;
+use React\Http\Io\BufferedBody;
+use React\Http\Io\HttpBodyStream;
+use React\Stream\ReadableStreamInterface;
+use RingCentral\Psr7\Response as Psr7Response;
+
+/**
+ * Represents an outgoing server response message.
+ *
+ * ```php
+ * $response = new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * array(
+ * 'Content-Type' => 'text/html'
+ * ),
+ * "<html>Hello world!</html>\n"
+ * );
+ * ```
+ *
+ * This class implements the
+ * [PSR-7 `ResponseInterface`](https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface)
+ * which in turn extends the
+ * [PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface).
+ *
+ * On top of this, this class implements the
+ * [PSR-7 Message Util `StatusCodeInterface`](https://github.com/php-fig/http-message-util/blob/master/src/StatusCodeInterface.php)
+ * which means that most common HTTP status codes are available as class
+ * constants with the `STATUS_*` prefix. For instance, the `200 OK` and
+ * `404 Not Found` status codes can used as `Response::STATUS_OK` and
+ * `Response::STATUS_NOT_FOUND` respectively.
+ *
+ * > Internally, this implementation builds on top of an existing incoming
+ * response message and only adds required streaming support. This base class is
+ * considered an implementation detail that may change in the future.
+ *
+ * @see \Psr\Http\Message\ResponseInterface
+ */
+final class Response extends Psr7Response implements StatusCodeInterface
+{
+ /**
+ * Create an HTML response
+ *
+ * ```php
+ * $html = <<<HTML
+ * <!doctype html>
+ * <html>
+ * <body>Hello wörld!</body>
+ * </html>
+ *
+ * HTML;
+ *
+ * $response = React\Http\Message\Response::html($html);
+ * ```
+ *
+ * This is a convenient shortcut method that returns the equivalent of this:
+ *
+ * ```
+ * $response = new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * [
+ * 'Content-Type' => 'text/html; charset=utf-8'
+ * ],
+ * $html
+ * );
+ * ```
+ *
+ * This method always returns a response with a `200 OK` status code and
+ * the appropriate `Content-Type` response header for the given HTTP source
+ * string encoded in UTF-8 (Unicode). It's generally recommended to end the
+ * given plaintext string with a trailing newline.
+ *
+ * If you want to use a different status code or custom HTTP response
+ * headers, you can manipulate the returned response object using the
+ * provided PSR-7 methods or directly instantiate a custom HTTP response
+ * object using the `Response` constructor:
+ *
+ * ```php
+ * $response = React\Http\Message\Response::html(
+ * "<h1>Error</h1>\n<p>Invalid user name given.</p>\n"
+ * )->withStatus(React\Http\Message\Response::STATUS_BAD_REQUEST);
+ * ```
+ *
+ * @param string $html
+ * @return self
+ */
+ public static function html($html)
+ {
+ return new self(self::STATUS_OK, array('Content-Type' => 'text/html; charset=utf-8'), $html);
+ }
+
+ /**
+ * Create a JSON response
+ *
+ * ```php
+ * $response = React\Http\Message\Response::json(['name' => 'Alice']);
+ * ```
+ *
+ * This is a convenient shortcut method that returns the equivalent of this:
+ *
+ * ```
+ * $response = new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * [
+ * 'Content-Type' => 'application/json'
+ * ],
+ * json_encode(
+ * ['name' => 'Alice'],
+ * JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION
+ * ) . "\n"
+ * );
+ * ```
+ *
+ * This method always returns a response with a `200 OK` status code and
+ * the appropriate `Content-Type` response header for the given structured
+ * data encoded as a JSON text.
+ *
+ * The given structured data will be encoded as a JSON text. Any `string`
+ * values in the data must be encoded in UTF-8 (Unicode). If the encoding
+ * fails, this method will throw an `InvalidArgumentException`.
+ *
+ * By default, the given structured data will be encoded with the flags as
+ * shown above. This includes pretty printing (PHP 5.4+) and preserving
+ * zero fractions for `float` values (PHP 5.6.6+) to ease debugging. It is
+ * assumed any additional data overhead is usually compensated by using HTTP
+ * response compression.
+ *
+ * If you want to use a different status code or custom HTTP response
+ * headers, you can manipulate the returned response object using the
+ * provided PSR-7 methods or directly instantiate a custom HTTP response
+ * object using the `Response` constructor:
+ *
+ * ```php
+ * $response = React\Http\Message\Response::json(
+ * ['error' => 'Invalid user name given']
+ * )->withStatus(React\Http\Message\Response::STATUS_BAD_REQUEST);
+ * ```
+ *
+ * @param mixed $data
+ * @return self
+ * @throws \InvalidArgumentException when encoding fails
+ */
+ public static function json($data)
+ {
+ $json = @\json_encode(
+ $data,
+ (\defined('JSON_PRETTY_PRINT') ? \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE : 0) | (\defined('JSON_PRESERVE_ZERO_FRACTION') ? \JSON_PRESERVE_ZERO_FRACTION : 0)
+ );
+
+ // throw on error, now `false` but used to be `(string) "null"` before PHP 5.5
+ if ($json === false || (\PHP_VERSION_ID < 50500 && \json_last_error() !== \JSON_ERROR_NONE)) {
+ throw new \InvalidArgumentException(
+ 'Unable to encode given data as JSON' . (\function_exists('json_last_error_msg') ? ': ' . \json_last_error_msg() : ''),
+ \json_last_error()
+ );
+ }
+
+ return new self(self::STATUS_OK, array('Content-Type' => 'application/json'), $json . "\n");
+ }
+
+ /**
+ * Create a plaintext response
+ *
+ * ```php
+ * $response = React\Http\Message\Response::plaintext("Hello wörld!\n");
+ * ```
+ *
+ * This is a convenient shortcut method that returns the equivalent of this:
+ *
+ * ```
+ * $response = new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * [
+ * 'Content-Type' => 'text/plain; charset=utf-8'
+ * ],
+ * "Hello wörld!\n"
+ * );
+ * ```
+ *
+ * This method always returns a response with a `200 OK` status code and
+ * the appropriate `Content-Type` response header for the given plaintext
+ * string encoded in UTF-8 (Unicode). It's generally recommended to end the
+ * given plaintext string with a trailing newline.
+ *
+ * If you want to use a different status code or custom HTTP response
+ * headers, you can manipulate the returned response object using the
+ * provided PSR-7 methods or directly instantiate a custom HTTP response
+ * object using the `Response` constructor:
+ *
+ * ```php
+ * $response = React\Http\Message\Response::plaintext(
+ * "Error: Invalid user name given.\n"
+ * )->withStatus(React\Http\Message\Response::STATUS_BAD_REQUEST);
+ * ```
+ *
+ * @param string $text
+ * @return self
+ */
+ public static function plaintext($text)
+ {
+ return new self(self::STATUS_OK, array('Content-Type' => 'text/plain; charset=utf-8'), $text);
+ }
+
+ /**
+ * Create an XML response
+ *
+ * ```php
+ * $xml = <<<XML
+ * <?xml version="1.0" encoding="utf-8"?>
+ * <body>
+ * <greeting>Hello wörld!</greeting>
+ * </body>
+ *
+ * XML;
+ *
+ * $response = React\Http\Message\Response::xml($xml);
+ * ```
+ *
+ * This is a convenient shortcut method that returns the equivalent of this:
+ *
+ * ```
+ * $response = new React\Http\Message\Response(
+ * React\Http\Message\Response::STATUS_OK,
+ * [
+ * 'Content-Type' => 'application/xml'
+ * ],
+ * $xml
+ * );
+ * ```
+ *
+ * This method always returns a response with a `200 OK` status code and
+ * the appropriate `Content-Type` response header for the given XML source
+ * string. It's generally recommended to use UTF-8 (Unicode) and specify
+ * this as part of the leading XML declaration and to end the given XML
+ * source string with a trailing newline.
+ *
+ * If you want to use a different status code or custom HTTP response
+ * headers, you can manipulate the returned response object using the
+ * provided PSR-7 methods or directly instantiate a custom HTTP response
+ * object using the `Response` constructor:
+ *
+ * ```php
+ * $response = React\Http\Message\Response::xml(
+ * "<error><message>Invalid user name given.</message></error>\n"
+ * )->withStatus(React\Http\Message\Response::STATUS_BAD_REQUEST);
+ * ```
+ *
+ * @param string $xml
+ * @return self
+ */
+ public static function xml($xml)
+ {
+ return new self(self::STATUS_OK, array('Content-Type' => 'application/xml'), $xml);
+ }
+
+ /**
+ * @param int $status HTTP status code (e.g. 200/404), see `self::STATUS_*` constants
+ * @param array<string,string|string[]> $headers additional response headers
+ * @param string|ReadableStreamInterface|StreamInterface $body response body
+ * @param string $version HTTP protocol version (e.g. 1.1/1.0)
+ * @param ?string $reason custom HTTP response phrase
+ * @throws \InvalidArgumentException for an invalid body
+ */
+ public function __construct(
+ $status = self::STATUS_OK,
+ array $headers = array(),
+ $body = '',
+ $version = '1.1',
+ $reason = null
+ ) {
+ if (\is_string($body)) {
+ $body = new BufferedBody($body);
+ } elseif ($body instanceof ReadableStreamInterface && !$body instanceof StreamInterface) {
+ $body = new HttpBodyStream($body, null);
+ } elseif (!$body instanceof StreamInterface) {
+ throw new \InvalidArgumentException('Invalid response body given');
+ }
+
+ parent::__construct(
+ $status,
+ $headers,
+ $body,
+ $version,
+ $reason
+ );
+ }
+}
diff --git a/vendor/react/http/src/Message/ResponseException.php b/vendor/react/http/src/Message/ResponseException.php
new file mode 100644
index 0000000..f4912c9
--- /dev/null
+++ b/vendor/react/http/src/Message/ResponseException.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace React\Http\Message;
+
+use RuntimeException;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * The `React\Http\Message\ResponseException` is an `Exception` sub-class that will be used to reject
+ * a request promise if the remote server returns a non-success status code
+ * (anything but 2xx or 3xx).
+ * You can control this behavior via the [`withRejectErrorResponse()` method](#withrejecterrorresponse).
+ *
+ * The `getCode(): int` method can be used to
+ * return the HTTP response status code.
+ */
+final class ResponseException extends RuntimeException
+{
+ private $response;
+
+ public function __construct(ResponseInterface $response, $message = null, $code = null, $previous = null)
+ {
+ if ($message === null) {
+ $message = 'HTTP status code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ')';
+ }
+ if ($code === null) {
+ $code = $response->getStatusCode();
+ }
+ parent::__construct($message, $code, $previous);
+
+ $this->response = $response;
+ }
+
+ /**
+ * Access its underlying response object.
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+}
diff --git a/vendor/react/http/src/Message/ServerRequest.php b/vendor/react/http/src/Message/ServerRequest.php
new file mode 100644
index 0000000..f446f24
--- /dev/null
+++ b/vendor/react/http/src/Message/ServerRequest.php
@@ -0,0 +1,197 @@
+<?php
+
+namespace React\Http\Message;
+
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+use React\Http\Io\BufferedBody;
+use React\Http\Io\HttpBodyStream;
+use React\Stream\ReadableStreamInterface;
+use RingCentral\Psr7\Request;
+
+/**
+ * Respresents an incoming server request message.
+ *
+ * This class implements the
+ * [PSR-7 `ServerRequestInterface`](https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface)
+ * which extends the
+ * [PSR-7 `RequestInterface`](https://www.php-fig.org/psr/psr-7/#32-psrhttpmessagerequestinterface)
+ * which in turn extends the
+ * [PSR-7 `MessageInterface`](https://www.php-fig.org/psr/psr-7/#31-psrhttpmessagemessageinterface).
+ *
+ * This is mostly used internally to represent each incoming request message.
+ * Likewise, you can also use this class in test cases to test how your web
+ * application reacts to certain HTTP requests.
+ *
+ * > Internally, this implementation builds on top of an existing outgoing
+ * request message and only adds required server methods. This base class is
+ * considered an implementation detail that may change in the future.
+ *
+ * @see ServerRequestInterface
+ */
+final class ServerRequest extends Request implements ServerRequestInterface
+{
+ private $attributes = array();
+
+ private $serverParams;
+ private $fileParams = array();
+ private $cookies = array();
+ private $queryParams = array();
+ private $parsedBody;
+
+ /**
+ * @param string $method HTTP method for the request.
+ * @param string|UriInterface $url URL for the request.
+ * @param array<string,string|string[]> $headers Headers for the message.
+ * @param string|ReadableStreamInterface|StreamInterface $body Message body.
+ * @param string $version HTTP protocol version.
+ * @param array<string,string> $serverParams server-side parameters
+ * @throws \InvalidArgumentException for an invalid URL or body
+ */
+ public function __construct(
+ $method,
+ $url,
+ array $headers = array(),
+ $body = '',
+ $version = '1.1',
+ $serverParams = array()
+ ) {
+ $stream = null;
+ if (\is_string($body)) {
+ $body = new BufferedBody($body);
+ } elseif ($body instanceof ReadableStreamInterface && !$body instanceof StreamInterface) {
+ $stream = $body;
+ $body = null;
+ } elseif (!$body instanceof StreamInterface) {
+ throw new \InvalidArgumentException('Invalid server request body given');
+ }
+
+ $this->serverParams = $serverParams;
+ parent::__construct($method, $url, $headers, $body, $version);
+
+ if ($stream !== null) {
+ $size = (int) $this->getHeaderLine('Content-Length');
+ if (\strtolower($this->getHeaderLine('Transfer-Encoding')) === 'chunked') {
+ $size = null;
+ }
+ $this->stream = new HttpBodyStream($stream, $size);
+ }
+
+ $query = $this->getUri()->getQuery();
+ if ($query !== '') {
+ \parse_str($query, $this->queryParams);
+ }
+
+ // Multiple cookie headers are not allowed according
+ // to https://tools.ietf.org/html/rfc6265#section-5.4
+ $cookieHeaders = $this->getHeader("Cookie");
+
+ if (count($cookieHeaders) === 1) {
+ $this->cookies = $this->parseCookie($cookieHeaders[0]);
+ }
+ }
+
+ public function getServerParams()
+ {
+ return $this->serverParams;
+ }
+
+ public function getCookieParams()
+ {
+ return $this->cookies;
+ }
+
+ public function withCookieParams(array $cookies)
+ {
+ $new = clone $this;
+ $new->cookies = $cookies;
+ return $new;
+ }
+
+ public function getQueryParams()
+ {
+ return $this->queryParams;
+ }
+
+ public function withQueryParams(array $query)
+ {
+ $new = clone $this;
+ $new->queryParams = $query;
+ return $new;
+ }
+
+ public function getUploadedFiles()
+ {
+ return $this->fileParams;
+ }
+
+ public function withUploadedFiles(array $uploadedFiles)
+ {
+ $new = clone $this;
+ $new->fileParams = $uploadedFiles;
+ return $new;
+ }
+
+ public function getParsedBody()
+ {
+ return $this->parsedBody;
+ }
+
+ public function withParsedBody($data)
+ {
+ $new = clone $this;
+ $new->parsedBody = $data;
+ return $new;
+ }
+
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function getAttribute($name, $default = null)
+ {
+ if (!\array_key_exists($name, $this->attributes)) {
+ return $default;
+ }
+ return $this->attributes[$name];
+ }
+
+ public function withAttribute($name, $value)
+ {
+ $new = clone $this;
+ $new->attributes[$name] = $value;
+ return $new;
+ }
+
+ public function withoutAttribute($name)
+ {
+ $new = clone $this;
+ unset($new->attributes[$name]);
+ return $new;
+ }
+
+ /**
+ * @param string $cookie
+ * @return array
+ */
+ private function parseCookie($cookie)
+ {
+ $cookieArray = \explode(';', $cookie);
+ $result = array();
+
+ foreach ($cookieArray as $pair) {
+ $pair = \trim($pair);
+ $nameValuePair = \explode('=', $pair, 2);
+
+ if (\count($nameValuePair) === 2) {
+ $key = \urldecode($nameValuePair[0]);
+ $value = \urldecode($nameValuePair[1]);
+ $result[$key] = $value;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/react/http/src/Middleware/LimitConcurrentRequestsMiddleware.php b/vendor/react/http/src/Middleware/LimitConcurrentRequestsMiddleware.php
new file mode 100644
index 0000000..5333810
--- /dev/null
+++ b/vendor/react/http/src/Middleware/LimitConcurrentRequestsMiddleware.php
@@ -0,0 +1,211 @@
+<?php
+
+namespace React\Http\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use React\Http\Io\HttpBodyStream;
+use React\Http\Io\PauseBufferStream;
+use React\Promise;
+use React\Promise\PromiseInterface;
+use React\Promise\Deferred;
+use React\Stream\ReadableStreamInterface;
+
+/**
+ * Limits how many next handlers can be executed concurrently.
+ *
+ * If this middleware is invoked, it will check if the number of pending
+ * handlers is below the allowed limit and then simply invoke the next handler
+ * and it will return whatever the next handler returns (or throws).
+ *
+ * If the number of pending handlers exceeds the allowed limit, the request will
+ * be queued (and its streaming body will be paused) and it will return a pending
+ * promise.
+ * Once a pending handler returns (or throws), it will pick the oldest request
+ * from this queue and invokes the next handler (and its streaming body will be
+ * resumed).
+ *
+ * The following example shows how this middleware can be used to ensure no more
+ * than 10 handlers will be invoked at once:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(10),
+ * $handler
+ * );
+ * ```
+ *
+ * Similarly, this middleware is often used in combination with the
+ * [`RequestBodyBufferMiddleware`](#requestbodybuffermiddleware) (see below)
+ * to limit the total number of requests that can be buffered at once:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+ * new React\Http\Middleware\RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+ * new React\Http\Middleware\RequestBodyParserMiddleware(),
+ * $handler
+ * );
+ * ```
+ *
+ * More sophisticated examples include limiting the total number of requests
+ * that can be buffered at once and then ensure the actual request handler only
+ * processes one request after another without any concurrency:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+ * new React\Http\Middleware\RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+ * new React\Http\Middleware\RequestBodyParserMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(1), // only execute 1 handler (no concurrency)
+ * $handler
+ * );
+ * ```
+ *
+ * @see RequestBodyBufferMiddleware
+ */
+final class LimitConcurrentRequestsMiddleware
+{
+ private $limit;
+ private $pending = 0;
+ private $queue = array();
+
+ /**
+ * @param int $limit Maximum amount of concurrent requests handled.
+ *
+ * For example when $limit is set to 10, 10 requests will flow to $next
+ * while more incoming requests have to wait until one is done.
+ */
+ public function __construct($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function __invoke(ServerRequestInterface $request, $next)
+ {
+ // happy path: simply invoke next request handler if we're below limit
+ if ($this->pending < $this->limit) {
+ ++$this->pending;
+
+ try {
+ $response = $next($request);
+ } catch (\Exception $e) {
+ $this->processQueue();
+ throw $e;
+ } catch (\Throwable $e) { // @codeCoverageIgnoreStart
+ // handle Errors just like Exceptions (PHP 7+ only)
+ $this->processQueue();
+ throw $e; // @codeCoverageIgnoreEnd
+ }
+
+ // happy path: if next request handler returned immediately,
+ // we can simply try to invoke the next queued request
+ if ($response instanceof ResponseInterface) {
+ $this->processQueue();
+ return $response;
+ }
+
+ // if the next handler returns a pending promise, we have to
+ // await its resolution before invoking next queued request
+ return $this->await(Promise\resolve($response));
+ }
+
+ // if we reach this point, then this request will need to be queued
+ // check if the body is streaming, in which case we need to buffer everything
+ $body = $request->getBody();
+ if ($body instanceof ReadableStreamInterface) {
+ // pause actual body to stop emitting data until the handler is called
+ $size = $body->getSize();
+ $body = new PauseBufferStream($body);
+ $body->pauseImplicit();
+
+ // replace with buffering body to ensure any readable events will be buffered
+ $request = $request->withBody(new HttpBodyStream(
+ $body,
+ $size
+ ));
+ }
+
+ // get next queue position
+ $queue =& $this->queue;
+ $queue[] = null;
+ \end($queue);
+ $id = \key($queue);
+
+ $deferred = new Deferred(function ($_, $reject) use (&$queue, $id) {
+ // queued promise cancelled before its next handler is invoked
+ // remove from queue and reject explicitly
+ unset($queue[$id]);
+ $reject(new \RuntimeException('Cancelled queued next handler'));
+ });
+
+ // queue request and process queue if pending does not exceed limit
+ $queue[$id] = $deferred;
+
+ $pending = &$this->pending;
+ $that = $this;
+ return $deferred->promise()->then(function () use ($request, $next, $body, &$pending, $that) {
+ // invoke next request handler
+ ++$pending;
+
+ try {
+ $response = $next($request);
+ } catch (\Exception $e) {
+ $that->processQueue();
+ throw $e;
+ } catch (\Throwable $e) { // @codeCoverageIgnoreStart
+ // handle Errors just like Exceptions (PHP 7+ only)
+ $that->processQueue();
+ throw $e; // @codeCoverageIgnoreEnd
+ }
+
+ // resume readable stream and replay buffered events
+ if ($body instanceof PauseBufferStream) {
+ $body->resumeImplicit();
+ }
+
+ // if the next handler returns a pending promise, we have to
+ // await its resolution before invoking next queued request
+ return $that->await(Promise\resolve($response));
+ });
+ }
+
+ /**
+ * @internal
+ * @param PromiseInterface $promise
+ * @return PromiseInterface
+ */
+ public function await(PromiseInterface $promise)
+ {
+ $that = $this;
+
+ return $promise->then(function ($response) use ($that) {
+ $that->processQueue();
+
+ return $response;
+ }, function ($error) use ($that) {
+ $that->processQueue();
+
+ return Promise\reject($error);
+ });
+ }
+
+ /**
+ * @internal
+ */
+ public function processQueue()
+ {
+ // skip if we're still above concurrency limit or there's no queued request waiting
+ if (--$this->pending >= $this->limit || !$this->queue) {
+ return;
+ }
+
+ $first = \reset($this->queue);
+ unset($this->queue[key($this->queue)]);
+
+ $first->resolve();
+ }
+}
diff --git a/vendor/react/http/src/Middleware/RequestBodyBufferMiddleware.php b/vendor/react/http/src/Middleware/RequestBodyBufferMiddleware.php
new file mode 100644
index 0000000..c13a5de
--- /dev/null
+++ b/vendor/react/http/src/Middleware/RequestBodyBufferMiddleware.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace React\Http\Middleware;
+
+use OverflowException;
+use Psr\Http\Message\ServerRequestInterface;
+use React\Http\Io\BufferedBody;
+use React\Http\Io\IniUtil;
+use React\Promise\Stream;
+use React\Stream\ReadableStreamInterface;
+
+final class RequestBodyBufferMiddleware
+{
+ private $sizeLimit;
+
+ /**
+ * @param int|string|null $sizeLimit Either an int with the max request body size
+ * in bytes or an ini like size string
+ * or null to use post_max_size from PHP's
+ * configuration. (Note that the value from
+ * the CLI configuration will be used.)
+ */
+ public function __construct($sizeLimit = null)
+ {
+ if ($sizeLimit === null) {
+ $sizeLimit = \ini_get('post_max_size');
+ }
+
+ $this->sizeLimit = IniUtil::iniSizeToBytes($sizeLimit);
+ }
+
+ public function __invoke(ServerRequestInterface $request, $stack)
+ {
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ // happy path: skip if body is known to be empty (or is already buffered)
+ if ($size === 0 || !$body instanceof ReadableStreamInterface) {
+ // replace with empty body if body is streaming (or buffered size exceeds limit)
+ if ($body instanceof ReadableStreamInterface || $size > $this->sizeLimit) {
+ $request = $request->withBody(new BufferedBody(''));
+ }
+
+ return $stack($request);
+ }
+
+ // request body of known size exceeding limit
+ $sizeLimit = $this->sizeLimit;
+ if ($size > $this->sizeLimit) {
+ $sizeLimit = 0;
+ }
+
+ return Stream\buffer($body, $sizeLimit)->then(function ($buffer) use ($request, $stack) {
+ $request = $request->withBody(new BufferedBody($buffer));
+
+ return $stack($request);
+ }, function ($error) use ($stack, $request, $body) {
+ // On buffer overflow keep the request body stream in,
+ // but ignore the contents and wait for the close event
+ // before passing the request on to the next middleware.
+ if ($error instanceof OverflowException) {
+ return Stream\first($body, 'close')->then(function () use ($stack, $request) {
+ return $stack($request);
+ });
+ }
+
+ throw $error;
+ });
+ }
+}
diff --git a/vendor/react/http/src/Middleware/RequestBodyParserMiddleware.php b/vendor/react/http/src/Middleware/RequestBodyParserMiddleware.php
new file mode 100644
index 0000000..be5ba16
--- /dev/null
+++ b/vendor/react/http/src/Middleware/RequestBodyParserMiddleware.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace React\Http\Middleware;
+
+use Psr\Http\Message\ServerRequestInterface;
+use React\Http\Io\MultipartParser;
+
+final class RequestBodyParserMiddleware
+{
+ private $multipart;
+
+ /**
+ * @param int|string|null $uploadMaxFilesize
+ * @param int|null $maxFileUploads
+ */
+ public function __construct($uploadMaxFilesize = null, $maxFileUploads = null)
+ {
+ $this->multipart = new MultipartParser($uploadMaxFilesize, $maxFileUploads);
+ }
+
+ public function __invoke(ServerRequestInterface $request, $next)
+ {
+ $type = \strtolower($request->getHeaderLine('Content-Type'));
+ list ($type) = \explode(';', $type);
+
+ if ($type === 'application/x-www-form-urlencoded') {
+ return $next($this->parseFormUrlencoded($request));
+ }
+
+ if ($type === 'multipart/form-data') {
+ return $next($this->multipart->parse($request));
+ }
+
+ return $next($request);
+ }
+
+ private function parseFormUrlencoded(ServerRequestInterface $request)
+ {
+ // parse string into array structure
+ // ignore warnings due to excessive data structures (max_input_vars and max_input_nesting_level)
+ $ret = array();
+ @\parse_str((string)$request->getBody(), $ret);
+
+ return $request->withParsedBody($ret);
+ }
+}
diff --git a/vendor/react/http/src/Middleware/StreamingRequestMiddleware.php b/vendor/react/http/src/Middleware/StreamingRequestMiddleware.php
new file mode 100644
index 0000000..6ab74b7
--- /dev/null
+++ b/vendor/react/http/src/Middleware/StreamingRequestMiddleware.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace React\Http\Middleware;
+
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Process incoming requests with a streaming request body (without buffering).
+ *
+ * This allows you to process requests of any size without buffering the request
+ * body in memory. Instead, it will represent the request body as a
+ * [`ReadableStreamInterface`](https://github.com/reactphp/stream#readablestreaminterface)
+ * that emit chunks of incoming data as it is received:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * function (Psr\Http\Message\ServerRequestInterface $request) {
+ * $body = $request->getBody();
+ * assert($body instanceof Psr\Http\Message\StreamInterface);
+ * assert($body instanceof React\Stream\ReadableStreamInterface);
+ *
+ * return new React\Promise\Promise(function ($resolve) use ($body) {
+ * $bytes = 0;
+ * $body->on('data', function ($chunk) use (&$bytes) {
+ * $bytes += \count($chunk);
+ * });
+ * $body->on('close', function () use (&$bytes, $resolve) {
+ * $resolve(new React\Http\Response(
+ * 200,
+ * [],
+ * "Received $bytes bytes\n"
+ * ));
+ * });
+ * });
+ * }
+ * );
+ * ```
+ *
+ * See also [streaming incoming request](../../README.md#streaming-incoming-request)
+ * for more details.
+ *
+ * Additionally, this middleware can be used in combination with the
+ * [`LimitConcurrentRequestsMiddleware`](#limitconcurrentrequestsmiddleware) and
+ * [`RequestBodyBufferMiddleware`](#requestbodybuffermiddleware) (see below)
+ * to explicitly configure the total number of requests that can be handled at
+ * once:
+ *
+ * ```php
+ * $http = new React\Http\HttpServer(
+ * new React\Http\Middleware\StreamingRequestMiddleware(),
+ * new React\Http\Middleware\LimitConcurrentRequestsMiddleware(100), // 100 concurrent buffering handlers
+ * new React\Http\Middleware\RequestBodyBufferMiddleware(2 * 1024 * 1024), // 2 MiB per request
+ * new React\Http\Middleware\RequestBodyParserMiddleware(),
+ * $handler
+ * );
+ * ```
+ *
+ * > Internally, this class is used as a "marker" to not trigger the default
+ * request buffering behavior in the `HttpServer`. It does not implement any logic
+ * on its own.
+ */
+final class StreamingRequestMiddleware
+{
+ public function __invoke(ServerRequestInterface $request, $next)
+ {
+ return $next($request);
+ }
+}
diff --git a/vendor/react/http/src/Server.php b/vendor/react/http/src/Server.php
new file mode 100644
index 0000000..9bb9cf7
--- /dev/null
+++ b/vendor/react/http/src/Server.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace React\Http;
+
+// Deprecated `Server` is an alias for new `HttpServer` to ensure existing code continues to work as-is.
+\class_alias(__NAMESPACE__ . '\\HttpServer', __NAMESPACE__ . '\\Server', true);
+
+// Aid static analysis and IDE autocompletion about this deprecation,
+// but don't actually execute during runtime because `HttpServer` is final.
+if (!\class_exists(__NAMESPACE__ . '\\Server', false)) {
+ /**
+ * @deprecated 1.5.0 See HttpServer instead
+ * @see HttpServer
+ */
+ final class Server extends HttpServer
+ {
+ }
+}
diff --git a/vendor/react/promise-stream/LICENSE b/vendor/react/promise-stream/LICENSE
new file mode 100644
index 0000000..25e7071
--- /dev/null
+++ b/vendor/react/promise-stream/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden
+
+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/react/promise-stream/composer.json b/vendor/react/promise-stream/composer.json
new file mode 100644
index 0000000..ee3972c
--- /dev/null
+++ b/vendor/react/promise-stream/composer.json
@@ -0,0 +1,47 @@
+{
+ "name": "react/promise-stream",
+ "description": "The missing link between Promise-land and Stream-land for ReactPHP",
+ "keywords": ["unwrap", "stream", "buffer", "promise", "ReactPHP", "async"],
+ "homepage": "https://github.com/reactphp/promise-stream",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "React\\Promise\\Stream\\" : "src/" },
+ "files": [ "src/functions_include.php" ]
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\Promise\\Stream\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6",
+ "react/promise": "^2.1 || ^1.2"
+ },
+ "require-dev": {
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise-timer": "^1.0",
+ "clue/block-react": "^1.0",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/react/promise-stream/src/UnwrapReadableStream.php b/vendor/react/promise-stream/src/UnwrapReadableStream.php
new file mode 100644
index 0000000..acd23be
--- /dev/null
+++ b/vendor/react/promise-stream/src/UnwrapReadableStream.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace React\Promise\Stream;
+
+use Evenement\EventEmitter;
+use InvalidArgumentException;
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\PromiseInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\Util;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @internal
+ * @see unwrapReadable() instead
+ */
+class UnwrapReadableStream extends EventEmitter implements ReadableStreamInterface
+{
+ private $promise;
+ private $closed = false;
+
+ /**
+ * Instantiate new unwrapped readable stream for given `Promise` which resolves with a `ReadableStreamInterface`.
+ *
+ * @param PromiseInterface $promise Promise<ReadableStreamInterface, Exception>
+ */
+ public function __construct(PromiseInterface $promise)
+ {
+ $out = $this;
+ $closed =& $this->closed;
+
+ $this->promise = $promise->then(
+ function ($stream) {
+ if (!$stream instanceof ReadableStreamInterface) {
+ throw new InvalidArgumentException('Not a readable stream');
+ }
+ return $stream;
+ }
+ )->then(
+ function (ReadableStreamInterface $stream) use ($out, &$closed) {
+ // stream is already closed, make sure to close output stream
+ if (!$stream->isReadable()) {
+ $out->close();
+ return $stream;
+ }
+
+ // resolves but output is already closed, make sure to close stream silently
+ if ($closed) {
+ $stream->close();
+ return $stream;
+ }
+
+ // stream any writes into output stream
+ $stream->on('data', function ($data) use ($out) {
+ $out->emit('data', array($data, $out));
+ });
+
+ // forward end events and close
+ $stream->on('end', function () use ($out, &$closed) {
+ if (!$closed) {
+ $out->emit('end', array($out));
+ $out->close();
+ }
+ });
+
+ // error events cancel output stream
+ $stream->on('error', function ($error) use ($out) {
+ $out->emit('error', array($error, $out));
+ $out->close();
+ });
+
+ // close both streams once either side closes
+ $stream->on('close', array($out, 'close'));
+ $out->on('close', array($stream, 'close'));
+
+ return $stream;
+ },
+ function ($e) use ($out, &$closed) {
+ if (!$closed) {
+ $out->emit('error', array($e, $out));
+ $out->close();
+ }
+
+ // resume() and pause() may attach to this promise, so ensure we actually reject here
+ throw $e;
+ }
+ );
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed;
+ }
+
+ public function pause()
+ {
+ if ($this->promise !== null) {
+ $this->promise->then(function (ReadableStreamInterface $stream) {
+ $stream->pause();
+ });
+ }
+ }
+
+ public function resume()
+ {
+ if ($this->promise !== null) {
+ $this->promise->then(function (ReadableStreamInterface $stream) {
+ $stream->resume();
+ });
+ }
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ Util::pipe($this, $dest, $options);
+
+ return $dest;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ // try to cancel promise once the stream closes
+ if ($this->promise instanceof CancellablePromiseInterface) {
+ $this->promise->cancel();
+ }
+ $this->promise = null;
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+}
diff --git a/vendor/react/promise-stream/src/UnwrapWritableStream.php b/vendor/react/promise-stream/src/UnwrapWritableStream.php
new file mode 100644
index 0000000..f19e706
--- /dev/null
+++ b/vendor/react/promise-stream/src/UnwrapWritableStream.php
@@ -0,0 +1,164 @@
+<?php
+
+namespace React\Promise\Stream;
+
+use Evenement\EventEmitter;
+use InvalidArgumentException;
+use React\Promise\CancellablePromiseInterface;
+use React\Promise\PromiseInterface;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * @internal
+ * @see unwrapWritable() instead
+ */
+class UnwrapWritableStream extends EventEmitter implements WritableStreamInterface
+{
+ private $promise;
+ private $stream;
+ private $buffer = array();
+ private $closed = false;
+ private $ending = false;
+
+ /**
+ * Instantiate new unwrapped writable stream for given `Promise` which resolves with a `WritableStreamInterface`.
+ *
+ * @param PromiseInterface $promise Promise<WritableStreamInterface, Exception>
+ */
+ public function __construct(PromiseInterface $promise)
+ {
+ $out = $this;
+ $store =& $this->stream;
+ $buffer =& $this->buffer;
+ $ending =& $this->ending;
+ $closed =& $this->closed;
+
+ $this->promise = $promise->then(
+ function ($stream) {
+ if (!$stream instanceof WritableStreamInterface) {
+ throw new InvalidArgumentException('Not a writable stream');
+ }
+ return $stream;
+ }
+ )->then(
+ function (WritableStreamInterface $stream) use ($out, &$store, &$buffer, &$ending, &$closed) {
+ // stream is already closed, make sure to close output stream
+ if (!$stream->isWritable()) {
+ $out->close();
+ return $stream;
+ }
+
+ // resolves but output is already closed, make sure to close stream silently
+ if ($closed) {
+ $stream->close();
+ return $stream;
+ }
+
+ // forward drain events for back pressure
+ $stream->on('drain', function () use ($out) {
+ $out->emit('drain', array($out));
+ });
+
+ // error events cancel output stream
+ $stream->on('error', function ($error) use ($out) {
+ $out->emit('error', array($error, $out));
+ $out->close();
+ });
+
+ // close both streams once either side closes
+ $stream->on('close', array($out, 'close'));
+ $out->on('close', array($stream, 'close'));
+
+ if ($buffer) {
+ // flush buffer to stream and check if its buffer is not exceeded
+ $drained = true;
+ foreach ($buffer as $chunk) {
+ if (!$stream->write($chunk)) {
+ $drained = false;
+ }
+ }
+ $buffer = array();
+
+ if ($drained) {
+ // signal drain event, because the output stream previous signalled a full buffer
+ $out->emit('drain', array($out));
+ }
+ }
+
+ if ($ending) {
+ $stream->end();
+ } else {
+ $store = $stream;
+ }
+
+ return $stream;
+ },
+ function ($e) use ($out, &$closed) {
+ if (!$closed) {
+ $out->emit('error', array($e, $out));
+ $out->close();
+ }
+ }
+ );
+ }
+
+ public function write($data)
+ {
+ if ($this->ending) {
+ return false;
+ }
+
+ // forward to inner stream if possible
+ if ($this->stream !== null) {
+ return $this->stream->write($data);
+ }
+
+ // append to buffer and signal the buffer is full
+ $this->buffer[] = $data;
+ return false;
+ }
+
+ public function end($data = null)
+ {
+ if ($this->ending) {
+ return;
+ }
+
+ $this->ending = true;
+
+ // forward to inner stream if possible
+ if ($this->stream !== null) {
+ return $this->stream->end($data);
+ }
+
+ // append to buffer
+ if ($data !== null) {
+ $this->buffer[] = $data;
+ }
+ }
+
+ public function isWritable()
+ {
+ return !$this->ending;
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->buffer = array();
+ $this->ending = true;
+ $this->closed = true;
+
+ // try to cancel promise once the stream closes
+ if ($this->promise instanceof CancellablePromiseInterface) {
+ $this->promise->cancel();
+ }
+ $this->promise = $this->stream = null;
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+}
diff --git a/vendor/react/promise-stream/src/functions.php b/vendor/react/promise-stream/src/functions.php
new file mode 100644
index 0000000..da66de8
--- /dev/null
+++ b/vendor/react/promise-stream/src/functions.php
@@ -0,0 +1,370 @@
+<?php
+
+namespace React\Promise\Stream;
+
+use Evenement\EventEmitterInterface;
+use React\Promise;
+use React\Promise\PromiseInterface;
+use React\Stream\ReadableStreamInterface;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * Create a `Promise` which will be fulfilled with the stream data buffer.
+ *
+ * ```php
+ * $stream = accessSomeJsonStream();
+ *
+ * React\Promise\Stream\buffer($stream)->then(function (string $contents) {
+ * var_dump(json_decode($contents));
+ * });
+ * ```
+ *
+ * The promise will be fulfilled with a `string` of all data chunks concatenated once the stream closes.
+ *
+ * The promise will be fulfilled with an empty `string` if the stream is already closed.
+ *
+ * The promise will be rejected with a `RuntimeException` if the stream emits an error.
+ *
+ * The promise will be rejected with a `RuntimeException` if it is cancelled.
+ *
+ * The optional `$maxLength` argument defaults to no limit. In case the maximum
+ * length is given and the stream emits more data before the end, the promise
+ * will be rejected with an `OverflowException`.
+ *
+ * ```php
+ * $stream = accessSomeToLargeStream();
+ *
+ * React\Promise\Stream\buffer($stream, 1024)->then(function ($contents) {
+ * var_dump(json_decode($contents));
+ * }, function ($error) {
+ * // Reaching here when the stream buffer goes above the max size,
+ * // in this example that is 1024 bytes,
+ * // or when the stream emits an error.
+ * });
+ * ```
+ *
+ * @param ReadableStreamInterface<string> $stream
+ * @param ?int $maxLength Maximum number of bytes to buffer or null for unlimited.
+ * @return PromiseInterface<string,\RuntimeException>
+ */
+function buffer(ReadableStreamInterface $stream, $maxLength = null)
+{
+ // stream already ended => resolve with empty buffer
+ if (!$stream->isReadable()) {
+ return Promise\resolve('');
+ }
+
+ $buffer = '';
+
+ $promise = new Promise\Promise(function ($resolve, $reject) use ($stream, $maxLength, &$buffer, &$bufferer) {
+ $bufferer = function ($data) use (&$buffer, $reject, $maxLength) {
+ $buffer .= $data;
+
+ if ($maxLength !== null && isset($buffer[$maxLength])) {
+ $reject(new \OverflowException('Buffer exceeded maximum length'));
+ }
+ };
+
+ $stream->on('data', $bufferer);
+
+ $stream->on('error', function (\Exception $e) use ($reject) {
+ $reject(new \RuntimeException(
+ 'An error occured on the underlying stream while buffering: ' . $e->getMessage(),
+ $e->getCode(),
+ $e
+ ));
+ });
+
+ $stream->on('close', function () use ($resolve, &$buffer) {
+ $resolve($buffer);
+ });
+ }, function ($_, $reject) {
+ $reject(new \RuntimeException('Cancelled buffering'));
+ });
+
+ return $promise->then(null, function (\Exception $error) use (&$buffer, $bufferer, $stream) {
+ // promise rejected => clear buffer and buffering
+ $buffer = '';
+ $stream->removeListener('data', $bufferer);
+
+ throw $error;
+ });
+}
+
+/**
+ * Create a `Promise` which will be fulfilled once the given event triggers for the first time.
+ *
+ * ```php
+ * $stream = accessSomeJsonStream();
+ *
+ * React\Promise\Stream\first($stream)->then(function (string $chunk) {
+ * echo 'The first chunk arrived: ' . $chunk;
+ * });
+ * ```
+ *
+ * The promise will be fulfilled with a `mixed` value of whatever the first event
+ * emitted or `null` if the event does not pass any data.
+ * If you do not pass a custom event name, then it will wait for the first "data"
+ * event.
+ * For common streams of type `ReadableStreamInterface<string>`, this means it will be
+ * fulfilled with a `string` containing the first data chunk.
+ *
+ * The promise will be rejected with a `RuntimeException` if the stream emits an error
+ * – unless you're waiting for the "error" event, in which case it will be fulfilled.
+ *
+ * The promise will be rejected with a `RuntimeException` once the stream closes
+ * – unless you're waiting for the "close" event, in which case it will be fulfilled.
+ *
+ * The promise will be rejected with a `RuntimeException` if the stream is already closed.
+ *
+ * The promise will be rejected with a `RuntimeException` if it is cancelled.
+ *
+ * @param ReadableStreamInterface|WritableStreamInterface $stream
+ * @param string $event
+ * @return PromiseInterface<mixed,\RuntimeException>
+ */
+function first(EventEmitterInterface $stream, $event = 'data')
+{
+ if ($stream instanceof ReadableStreamInterface) {
+ // readable or duplex stream not readable => already closed
+ // a half-open duplex stream is considered closed if its readable side is closed
+ if (!$stream->isReadable()) {
+ return Promise\reject(new \RuntimeException('Stream already closed'));
+ }
+ } elseif ($stream instanceof WritableStreamInterface) {
+ // writable-only stream (not duplex) not writable => already closed
+ if (!$stream->isWritable()) {
+ return Promise\reject(new \RuntimeException('Stream already closed'));
+ }
+ }
+
+ return new Promise\Promise(function ($resolve, $reject) use ($stream, $event, &$listener) {
+ $listener = function ($data = null) use ($stream, $event, &$listener, $resolve) {
+ $stream->removeListener($event, $listener);
+ $resolve($data);
+ };
+ $stream->on($event, $listener);
+
+ if ($event !== 'error') {
+ $stream->on('error', function (\Exception $e) use ($stream, $event, $listener, $reject) {
+ $stream->removeListener($event, $listener);
+ $reject(new \RuntimeException(
+ 'An error occured on the underlying stream while waiting for event: ' . $e->getMessage(),
+ $e->getCode(),
+ $e
+ ));
+ });
+ }
+
+ $stream->on('close', function () use ($stream, $event, $listener, $reject) {
+ $stream->removeListener($event, $listener);
+ $reject(new \RuntimeException('Stream closed'));
+ });
+ }, function ($_, $reject) use ($stream, $event, &$listener) {
+ $stream->removeListener($event, $listener);
+ $reject(new \RuntimeException('Operation cancelled'));
+ });
+}
+
+/**
+ * Create a `Promise` which will be fulfilled with an array of all the event data.
+ *
+ * ```php
+ * $stream = accessSomeJsonStream();
+ *
+ * React\Promise\Stream\all($stream)->then(function (array $chunks) {
+ * echo 'The stream consists of ' . count($chunks) . ' chunk(s)';
+ * });
+ * ```
+ *
+ * The promise will be fulfilled with an `array` once the stream closes. The array
+ * will contain whatever all events emitted or `null` values if the events do not pass any data.
+ * If you do not pass a custom event name, then it will wait for all the "data"
+ * events.
+ * For common streams of type `ReadableStreamInterface<string>`, this means it will be
+ * fulfilled with a `string[]` array containing all the data chunk.
+ *
+ * The promise will be fulfilled with an empty `array` if the stream is already closed.
+ *
+ * The promise will be rejected with a `RuntimeException` if the stream emits an error.
+ *
+ * The promise will be rejected with a `RuntimeException` if it is cancelled.
+ *
+ * @param ReadableStreamInterface|WritableStreamInterface $stream
+ * @param string $event
+ * @return PromiseInterface<array,\RuntimeException>
+ */
+function all(EventEmitterInterface $stream, $event = 'data')
+{
+ // stream already ended => resolve with empty buffer
+ if ($stream instanceof ReadableStreamInterface) {
+ // readable or duplex stream not readable => already closed
+ // a half-open duplex stream is considered closed if its readable side is closed
+ if (!$stream->isReadable()) {
+ return Promise\resolve(array());
+ }
+ } elseif ($stream instanceof WritableStreamInterface) {
+ // writable-only stream (not duplex) not writable => already closed
+ if (!$stream->isWritable()) {
+ return Promise\resolve(array());
+ }
+ }
+
+ $buffer = array();
+ $bufferer = function ($data = null) use (&$buffer) {
+ $buffer []= $data;
+ };
+ $stream->on($event, $bufferer);
+
+ $promise = new Promise\Promise(function ($resolve, $reject) use ($stream, &$buffer) {
+ $stream->on('error', function (\Exception $e) use ($reject) {
+ $reject(new \RuntimeException(
+ 'An error occured on the underlying stream while buffering: ' . $e->getMessage(),
+ $e->getCode(),
+ $e
+ ));
+ });
+
+ $stream->on('close', function () use ($resolve, &$buffer) {
+ $resolve($buffer);
+ });
+ }, function ($_, $reject) {
+ $reject(new \RuntimeException('Cancelled buffering'));
+ });
+
+ return $promise->then(null, function ($error) use (&$buffer, $bufferer, $stream, $event) {
+ // promise rejected => clear buffer and buffering
+ $buffer = array();
+ $stream->removeListener($event, $bufferer);
+
+ throw $error;
+ });
+}
+
+/**
+ * Unwrap a `Promise` which will be fulfilled with a `ReadableStreamInterface<T>`.
+ *
+ * This function returns a readable stream instance (implementing `ReadableStreamInterface<T>`)
+ * right away which acts as a proxy for the future promise resolution.
+ * Once the given Promise will be fulfilled with a `ReadableStreamInterface<T>`, its
+ * data will be piped to the output stream.
+ *
+ * ```php
+ * //$promise = someFunctionWhichResolvesWithAStream();
+ * $promise = startDownloadStream($uri);
+ *
+ * $stream = React\Promise\Stream\unwrapReadable($promise);
+ *
+ * $stream->on('data', function (string $data) {
+ * echo $data;
+ * });
+ *
+ * $stream->on('end', function () {
+ * echo 'DONE';
+ * });
+ * ```
+ *
+ * If the given promise is either rejected or fulfilled with anything but an
+ * instance of `ReadableStreamInterface`, then the output stream will emit
+ * an `error` event and close:
+ *
+ * ```php
+ * $promise = startDownloadStream($invalidUri);
+ *
+ * $stream = React\Promise\Stream\unwrapReadable($promise);
+ *
+ * $stream->on('error', function (Exception $error) {
+ * echo 'Error: ' . $error->getMessage();
+ * });
+ * ```
+ *
+ * The given `$promise` SHOULD be pending, i.e. it SHOULD NOT be fulfilled or rejected
+ * at the time of invoking this function.
+ * If the given promise is already settled and does not fulfill with an instance of
+ * `ReadableStreamInterface`, then you will not be able to receive the `error` event.
+ *
+ * You can `close()` the resulting stream at any time, which will either try to
+ * `cancel()` the pending promise or try to `close()` the underlying stream.
+ *
+ * ```php
+ * $promise = startDownloadStream($uri);
+ *
+ * $stream = React\Promise\Stream\unwrapReadable($promise);
+ *
+ * $loop->addTimer(2.0, function () use ($stream) {
+ * $stream->close();
+ * });
+ * ```
+ *
+ * @param PromiseInterface<ReadableStreamInterface<T>,\Exception> $promise
+ * @return ReadableStreamInterface<T>
+ */
+function unwrapReadable(PromiseInterface $promise)
+{
+ return new UnwrapReadableStream($promise);
+}
+
+/**
+ * unwrap a `Promise` which will be fulfilled with a `WritableStreamInterface<T>`.
+ *
+ * This function returns a writable stream instance (implementing `WritableStreamInterface<T>`)
+ * right away which acts as a proxy for the future promise resolution.
+ * Any writes to this instance will be buffered in memory for when the promise will
+ * be fulfilled.
+ * Once the given Promise will be fulfilled with a `WritableStreamInterface<T>`, any
+ * data you have written to the proxy will be forwarded transparently to the inner
+ * stream.
+ *
+ * ```php
+ * //$promise = someFunctionWhichResolvesWithAStream();
+ * $promise = startUploadStream($uri);
+ *
+ * $stream = React\Promise\Stream\unwrapWritable($promise);
+ *
+ * $stream->write('hello');
+ * $stream->end('world');
+ *
+ * $stream->on('close', function () {
+ * echo 'DONE';
+ * });
+ * ```
+ *
+ * If the given promise is either rejected or fulfilled with anything but an
+ * instance of `WritableStreamInterface`, then the output stream will emit
+ * an `error` event and close:
+ *
+ * ```php
+ * $promise = startUploadStream($invalidUri);
+ *
+ * $stream = React\Promise\Stream\unwrapWritable($promise);
+ *
+ * $stream->on('error', function (Exception $error) {
+ * echo 'Error: ' . $error->getMessage();
+ * });
+ * ```
+ *
+ * The given `$promise` SHOULD be pending, i.e. it SHOULD NOT be fulfilled or rejected
+ * at the time of invoking this function.
+ * If the given promise is already settled and does not fulfill with an instance of
+ * `WritableStreamInterface`, then you will not be able to receive the `error` event.
+ *
+ * You can `close()` the resulting stream at any time, which will either try to
+ * `cancel()` the pending promise or try to `close()` the underlying stream.
+ *
+ * ```php
+ * $promise = startUploadStream($uri);
+ *
+ * $stream = React\Promise\Stream\unwrapWritable($promise);
+ *
+ * $loop->addTimer(2.0, function () use ($stream) {
+ * $stream->close();
+ * });
+ * ```
+ *
+ * @param PromiseInterface<WritableStreamInterface<T>,\Exception> $promise
+ * @return WritableStreamInterface<T>
+ */
+function unwrapWritable(PromiseInterface $promise)
+{
+ return new UnwrapWritableStream($promise);
+}
diff --git a/vendor/react/promise-stream/src/functions_include.php b/vendor/react/promise-stream/src/functions_include.php
new file mode 100644
index 0000000..768a4fd
--- /dev/null
+++ b/vendor/react/promise-stream/src/functions_include.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Promise\Stream;
+
+if (!function_exists('React\Promise\Stream\buffer')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/react/promise-timer/LICENSE b/vendor/react/promise-timer/LICENSE
new file mode 100644
index 0000000..56119ec
--- /dev/null
+++ b/vendor/react/promise-timer/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden
+
+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/react/promise-timer/composer.json b/vendor/react/promise-timer/composer.json
new file mode 100644
index 0000000..7335298
--- /dev/null
+++ b/vendor/react/promise-timer/composer.json
@@ -0,0 +1,44 @@
+{
+ "name": "react/promise-timer",
+ "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+ "keywords": ["Promise", "timeout", "timer", "event-loop", "ReactPHP", "async"],
+ "homepage": "https://github.com/reactphp/promise-timer",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "React\\Promise\\Timer\\": "src/" },
+ "files": [ "src/functions_include.php" ]
+ },
+ "autoload-dev": {
+ "psr-4": { "React\\Tests\\Promise\\Timer\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ }
+}
diff --git a/vendor/react/promise-timer/src/TimeoutException.php b/vendor/react/promise-timer/src/TimeoutException.php
new file mode 100644
index 0000000..7f03ba0
--- /dev/null
+++ b/vendor/react/promise-timer/src/TimeoutException.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace React\Promise\Timer;
+
+use RuntimeException;
+
+class TimeoutException extends RuntimeException
+{
+ /** @var float */
+ private $timeout;
+
+ /**
+ * @param float $timeout
+ * @param string|null $message
+ * @param int|null $code
+ * @param null|\Exception|\Throwable $previous
+ */
+ public function __construct($timeout, $message = '', $code = 0, $previous = null)
+ {
+ // Preserve compatibility with our former nullable signature, but avoid invalid arguments for the parent constructor:
+ parent::__construct((string) $message, (int) $code, $previous);
+
+ $this->timeout = (float) $timeout;
+ }
+
+ /**
+ * Get the timeout value in seconds.
+ *
+ * @return float
+ */
+ public function getTimeout()
+ {
+ return $this->timeout;
+ }
+}
diff --git a/vendor/react/promise-timer/src/functions.php b/vendor/react/promise-timer/src/functions.php
new file mode 100644
index 0000000..b72bf36
--- /dev/null
+++ b/vendor/react/promise-timer/src/functions.php
@@ -0,0 +1,330 @@
+<?php
+
+namespace React\Promise\Timer;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Promise;
+use React\Promise\PromiseInterface;
+
+/**
+ * Cancel operations that take *too long*.
+ *
+ * You need to pass in an input `$promise` that represents a pending operation
+ * and timeout parameters. It returns a new promise with the following
+ * resolution behavior:
+ *
+ * - If the input `$promise` resolves before `$time` seconds, resolve the
+ * resulting promise with its fulfillment value.
+ *
+ * - If the input `$promise` rejects before `$time` seconds, reject the
+ * resulting promise with its rejection value.
+ *
+ * - If the input `$promise` does not settle before `$time` seconds, *cancel*
+ * the operation and reject the resulting promise with a [`TimeoutException`](#timeoutexception).
+ *
+ * Internally, the given `$time` value will be used to start a timer that will
+ * *cancel* the pending operation once it triggers. This implies that if you
+ * pass a really small (or negative) value, it will still start a timer and will
+ * thus trigger at the earliest possible time in the future.
+ *
+ * If the input `$promise` is already settled, then the resulting promise will
+ * resolve or reject immediately without starting a timer at all.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * A common use case for handling only resolved values looks like this:
+ *
+ * ```php
+ * $promise = accessSomeRemoteResource();
+ * React\Promise\Timer\timeout($promise, 10.0)->then(function ($value) {
+ * // the operation finished within 10.0 seconds
+ * });
+ * ```
+ *
+ * A more complete example could look like this:
+ *
+ * ```php
+ * $promise = accessSomeRemoteResource();
+ * React\Promise\Timer\timeout($promise, 10.0)->then(
+ * function ($value) {
+ * // the operation finished within 10.0 seconds
+ * },
+ * function ($error) {
+ * if ($error instanceof React\Promise\Timer\TimeoutException) {
+ * // the operation has failed due to a timeout
+ * } else {
+ * // the input operation has failed due to some other error
+ * }
+ * }
+ * );
+ * ```
+ *
+ * Or if you're using [react/promise v3](https://github.com/reactphp/promise):
+ *
+ * ```php
+ * React\Promise\Timer\timeout($promise, 10.0)->then(function ($value) {
+ * // the operation finished within 10.0 seconds
+ * })->catch(function (React\Promise\Timer\TimeoutException $error) {
+ * // the operation has failed due to a timeout
+ * })->catch(function (Throwable $error) {
+ * // the input operation has failed due to some other error
+ * });
+ * ```
+ *
+ * As discussed above, the [`timeout()`](#timeout) function will take care of
+ * the underlying operation if it takes *too long*. In this case, you can be
+ * sure the resulting promise will always be rejected with a
+ * [`TimeoutException`](#timeoutexception). On top of this, the function will
+ * try to *cancel* the underlying operation. Responsibility for this
+ * cancellation logic is left up to the underlying operation.
+ *
+ * - A common use case involves cleaning up any resources like open network
+ * sockets or file handles or terminating external processes or timers.
+ *
+ * - If the given input `$promise` does not support cancellation, then this is a
+ * NO-OP. This means that while the resulting promise will still be rejected,
+ * the underlying input `$promise` may still be pending and can hence continue
+ * consuming resources
+ *
+ * On top of this, the returned promise is implemented in such a way that it can
+ * be cancelled when it is still pending. Cancelling a pending promise will
+ * cancel the underlying operation. As discussed above, responsibility for this
+ * cancellation logic is left up to the underlying operation.
+ *
+ * ```php
+ * $promise = accessSomeRemoteResource();
+ * $timeout = React\Promise\Timer\timeout($promise, 10.0);
+ *
+ * $timeout->cancel();
+ * ```
+ *
+ * For more details on the promise cancellation, please refer to the
+ * [Promise documentation](https://github.com/reactphp/promise#cancellablepromiseinterface).
+ *
+ * If you want to wait for multiple promises to resolve, you can use the normal
+ * promise primitives like this:
+ *
+ * ```php
+ * $promises = array(
+ * accessSomeRemoteResource(),
+ * accessSomeRemoteResource(),
+ * accessSomeRemoteResource()
+ * );
+ *
+ * $promise = React\Promise\all($promises);
+ *
+ * React\Promise\Timer\timeout($promise, 10)->then(function ($values) {
+ * // *all* promises resolved
+ * });
+ * ```
+ *
+ * The applies to all promise collection primitives alike, i.e. `all()`,
+ * `race()`, `any()`, `some()` etc.
+ *
+ * For more details on the promise primitives, please refer to the
+ * [Promise documentation](https://github.com/reactphp/promise#functions).
+ *
+ * @param PromiseInterface<mixed, \Throwable|mixed> $promise
+ * @param float $time
+ * @param ?LoopInterface $loop
+ * @return PromiseInterface<mixed, TimeoutException|\Throwable|mixed>
+ */
+function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null)
+{
+ // cancelling this promise will only try to cancel the input promise,
+ // thus leaving responsibility to the input promise.
+ $canceller = null;
+ if (\method_exists($promise, 'cancel')) {
+ // pass promise by reference to clean reference after cancellation handler
+ // has been invoked once in order to avoid garbage references in call stack.
+ $canceller = function () use (&$promise) {
+ $promise->cancel();
+ $promise = null;
+ };
+ }
+
+ if ($loop === null) {
+ $loop = Loop::get();
+ }
+
+ return new Promise(function ($resolve, $reject) use ($loop, $time, $promise) {
+ $timer = null;
+ $promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
+ if ($timer) {
+ $loop->cancelTimer($timer);
+ }
+ $timer = false;
+ $resolve($v);
+ }, function ($v) use (&$timer, $loop, $reject) {
+ if ($timer) {
+ $loop->cancelTimer($timer);
+ }
+ $timer = false;
+ $reject($v);
+ });
+
+ // promise already resolved => no need to start timer
+ if ($timer === false) {
+ return;
+ }
+
+ // start timeout timer which will cancel the input promise
+ $timer = $loop->addTimer($time, function () use ($time, &$promise, $reject) {
+ $reject(new TimeoutException($time, 'Timed out after ' . $time . ' seconds'));
+
+ // try to invoke cancellation handler of input promise and then clean
+ // reference in order to avoid garbage references in call stack.
+ if (\method_exists($promise, 'cancel')) {
+ $promise->cancel();
+ }
+ $promise = null;
+ });
+ }, $canceller);
+}
+
+/**
+ * Create a new promise that resolves in `$time` seconds.
+ *
+ * ```php
+ * React\Promise\Timer\sleep(1.5)->then(function () {
+ * echo 'Thanks for waiting!' . PHP_EOL;
+ * });
+ * ```
+ *
+ * Internally, the given `$time` value will be used to start a timer that will
+ * resolve the promise once it triggers. This implies that if you pass a really
+ * small (or negative) value, it will still start a timer and will thus trigger
+ * at the earliest possible time in the future.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * The returned promise is implemented in such a way that it can be cancelled
+ * when it is still pending. Cancelling a pending promise will reject its value
+ * with a `RuntimeException` and clean up any pending timers.
+ *
+ * ```php
+ * $timer = React\Promise\Timer\sleep(2.0);
+ *
+ * $timer->cancel();
+ * ```
+ *
+ * @param float $time
+ * @param ?LoopInterface $loop
+ * @return PromiseInterface<void, \RuntimeException>
+ */
+function sleep($time, LoopInterface $loop = null)
+{
+ if ($loop === null) {
+ $loop = Loop::get();
+ }
+
+ $timer = null;
+ return new Promise(function ($resolve) use ($loop, $time, &$timer) {
+ // resolve the promise when the timer fires in $time seconds
+ $timer = $loop->addTimer($time, function () use ($resolve) {
+ $resolve(null);
+ });
+ }, function () use (&$timer, $loop) {
+ // cancelling this promise will cancel the timer, clean the reference
+ // in order to avoid garbage references in call stack and then reject.
+ $loop->cancelTimer($timer);
+ $timer = null;
+
+ throw new \RuntimeException('Timer cancelled');
+ });
+}
+
+/**
+ * [Deprecated] Create a new promise that resolves in `$time` seconds with the `$time` as the fulfillment value.
+ *
+ * ```php
+ * React\Promise\Timer\resolve(1.5)->then(function ($time) {
+ * echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
+ * });
+ * ```
+ *
+ * Internally, the given `$time` value will be used to start a timer that will
+ * resolve the promise once it triggers. This implies that if you pass a really
+ * small (or negative) value, it will still start a timer and will thus trigger
+ * at the earliest possible time in the future.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * The returned promise is implemented in such a way that it can be cancelled
+ * when it is still pending. Cancelling a pending promise will reject its value
+ * with a `RuntimeException` and clean up any pending timers.
+ *
+ * ```php
+ * $timer = React\Promise\Timer\resolve(2.0);
+ *
+ * $timer->cancel();
+ * ```
+ *
+ * @param float $time
+ * @param ?LoopInterface $loop
+ * @return PromiseInterface<float, \RuntimeException>
+ * @deprecated 1.8.0 See `sleep()` instead
+ * @see sleep()
+ */
+function resolve($time, LoopInterface $loop = null)
+{
+ return sleep($time, $loop)->then(function() use ($time) {
+ return $time;
+ });
+}
+
+/**
+ * [Deprecated] Create a new promise which rejects in `$time` seconds with a `TimeoutException`.
+ *
+ * ```php
+ * React\Promise\Timer\reject(2.0)->then(null, function (React\Promise\Timer\TimeoutException $e) {
+ * echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
+ * });
+ * ```
+ *
+ * Internally, the given `$time` value will be used to start a timer that will
+ * reject the promise once it triggers. This implies that if you pass a really
+ * small (or negative) value, it will still start a timer and will thus trigger
+ * at the earliest possible time in the future.
+ *
+ * This function takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use. You can use a `null` value here in order to
+ * use the [default loop](https://github.com/reactphp/event-loop#loop). This value
+ * SHOULD NOT be given unless you're sure you want to explicitly use a given event
+ * loop instance.
+ *
+ * The returned promise is implemented in such a way that it can be cancelled
+ * when it is still pending. Cancelling a pending promise will reject its value
+ * with a `RuntimeException` and clean up any pending timers.
+ *
+ * ```php
+ * $timer = React\Promise\Timer\reject(2.0);
+ *
+ * $timer->cancel();
+ * ```
+ *
+ * @param float $time
+ * @param LoopInterface $loop
+ * @return PromiseInterface<void, TimeoutException|\RuntimeException>
+ * @deprecated 1.8.0 See `sleep()` instead
+ * @see sleep()
+ */
+function reject($time, LoopInterface $loop = null)
+{
+ return sleep($time, $loop)->then(function () use ($time) {
+ throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
+ });
+}
diff --git a/vendor/react/promise-timer/src/functions_include.php b/vendor/react/promise-timer/src/functions_include.php
new file mode 100644
index 0000000..1d5673a
--- /dev/null
+++ b/vendor/react/promise-timer/src/functions_include.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Promise\Timer;
+
+if (!function_exists('React\\Promise\\Timer\\timeout')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/react/promise/LICENSE b/vendor/react/promise/LICENSE
new file mode 100644
index 0000000..21c1357
--- /dev/null
+++ b/vendor/react/promise/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Jan Sorgalla, Christian Lück, Cees-Jan Kiewiet, Chris Boden
+
+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/react/promise/composer.json b/vendor/react/promise/composer.json
new file mode 100644
index 0000000..f933f15
--- /dev/null
+++ b/vendor/react/promise/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "react/promise",
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
+ },
+ "autoload": {
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Promise\\": ["tests", "tests/fixtures"]
+ }
+ },
+ "keywords": [
+ "promise",
+ "promises"
+ ]
+}
diff --git a/vendor/react/promise/src/CancellablePromiseInterface.php b/vendor/react/promise/src/CancellablePromiseInterface.php
new file mode 100644
index 0000000..6b3a8c6
--- /dev/null
+++ b/vendor/react/promise/src/CancellablePromiseInterface.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace React\Promise;
+
+interface CancellablePromiseInterface extends PromiseInterface
+{
+ /**
+ * The `cancel()` method notifies the creator of the promise that there is no
+ * further interest in the results of the operation.
+ *
+ * Once a promise is settled (either fulfilled or rejected), calling `cancel()` on
+ * a promise has no effect.
+ *
+ * @return void
+ */
+ public function cancel();
+}
diff --git a/vendor/react/promise/src/CancellationQueue.php b/vendor/react/promise/src/CancellationQueue.php
new file mode 100644
index 0000000..a381e97
--- /dev/null
+++ b/vendor/react/promise/src/CancellationQueue.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace React\Promise;
+
+class CancellationQueue
+{
+ private $started = false;
+ private $queue = [];
+
+ public function __invoke()
+ {
+ if ($this->started) {
+ return;
+ }
+
+ $this->started = true;
+ $this->drain();
+ }
+
+ public function enqueue($cancellable)
+ {
+ if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) {
+ return;
+ }
+
+ $length = \array_push($this->queue, $cancellable);
+
+ if ($this->started && 1 === $length) {
+ $this->drain();
+ }
+ }
+
+ private function drain()
+ {
+ for ($i = key($this->queue); isset($this->queue[$i]); $i++) {
+ $cancellable = $this->queue[$i];
+
+ $exception = null;
+
+ try {
+ $cancellable->cancel();
+ } catch (\Throwable $exception) {
+ } catch (\Exception $exception) {
+ }
+
+ unset($this->queue[$i]);
+
+ if ($exception) {
+ throw $exception;
+ }
+ }
+
+ $this->queue = [];
+ }
+}
diff --git a/vendor/react/promise/src/Deferred.php b/vendor/react/promise/src/Deferred.php
new file mode 100644
index 0000000..3ca034b
--- /dev/null
+++ b/vendor/react/promise/src/Deferred.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace React\Promise;
+
+class Deferred implements PromisorInterface
+{
+ private $promise;
+ private $resolveCallback;
+ private $rejectCallback;
+ private $notifyCallback;
+ private $canceller;
+
+ public function __construct(callable $canceller = null)
+ {
+ $this->canceller = $canceller;
+ }
+
+ public function promise()
+ {
+ if (null === $this->promise) {
+ $this->promise = new Promise(function ($resolve, $reject, $notify) {
+ $this->resolveCallback = $resolve;
+ $this->rejectCallback = $reject;
+ $this->notifyCallback = $notify;
+ }, $this->canceller);
+ $this->canceller = null;
+ }
+
+ return $this->promise;
+ }
+
+ public function resolve($value = null)
+ {
+ $this->promise();
+
+ \call_user_func($this->resolveCallback, $value);
+ }
+
+ public function reject($reason = null)
+ {
+ $this->promise();
+
+ \call_user_func($this->rejectCallback, $reason);
+ }
+
+ /**
+ * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore.
+ * @param mixed $update
+ */
+ public function notify($update = null)
+ {
+ $this->promise();
+
+ \call_user_func($this->notifyCallback, $update);
+ }
+
+ /**
+ * @deprecated 2.2.0
+ * @see Deferred::notify()
+ */
+ public function progress($update = null)
+ {
+ $this->notify($update);
+ }
+}
diff --git a/vendor/react/promise/src/Exception/LengthException.php b/vendor/react/promise/src/Exception/LengthException.php
new file mode 100644
index 0000000..775c48d
--- /dev/null
+++ b/vendor/react/promise/src/Exception/LengthException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace React\Promise\Exception;
+
+class LengthException extends \LengthException
+{
+}
diff --git a/vendor/react/promise/src/ExtendedPromiseInterface.php b/vendor/react/promise/src/ExtendedPromiseInterface.php
new file mode 100644
index 0000000..13b6369
--- /dev/null
+++ b/vendor/react/promise/src/ExtendedPromiseInterface.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace React\Promise;
+
+interface ExtendedPromiseInterface extends PromiseInterface
+{
+ /**
+ * Consumes the promise's ultimate value if the promise fulfills, or handles the
+ * ultimate error.
+ *
+ * It will cause a fatal error if either `$onFulfilled` or
+ * `$onRejected` throw or return a rejected promise.
+ *
+ * Since the purpose of `done()` is consumption rather than transformation,
+ * `done()` always returns `null`.
+ *
+ * @param callable|null $onFulfilled
+ * @param callable|null $onRejected
+ * @param callable|null $onProgress This argument is deprecated and should not be used anymore.
+ * @return void
+ */
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+
+ /**
+ * Registers a rejection handler for promise. It is a shortcut for:
+ *
+ * ```php
+ * $promise->then(null, $onRejected);
+ * ```
+ *
+ * Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
+ * only specific errors.
+ *
+ * @param callable $onRejected
+ * @return ExtendedPromiseInterface
+ */
+ public function otherwise(callable $onRejected);
+
+ /**
+ * Allows you to execute "cleanup" type tasks in a promise chain.
+ *
+ * It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
+ * when the promise is either fulfilled or rejected.
+ *
+ * * If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
+ * `$newPromise` will fulfill with the same value as `$promise`.
+ * * If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
+ * rejected promise, `$newPromise` will reject with the thrown exception or
+ * rejected promise's reason.
+ * * If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
+ * `$newPromise` will reject with the same reason as `$promise`.
+ * * If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
+ * rejected promise, `$newPromise` will reject with the thrown exception or
+ * rejected promise's reason.
+ *
+ * `always()` behaves similarly to the synchronous finally statement. When combined
+ * with `otherwise()`, `always()` allows you to write code that is similar to the familiar
+ * synchronous catch/finally pair.
+ *
+ * Consider the following synchronous code:
+ *
+ * ```php
+ * try {
+ * return doSomething();
+ * } catch(\Exception $e) {
+ * return handleError($e);
+ * } finally {
+ * cleanup();
+ * }
+ * ```
+ *
+ * Similar asynchronous code (with `doSomething()` that returns a promise) can be
+ * written:
+ *
+ * ```php
+ * return doSomething()
+ * ->otherwise('handleError')
+ * ->always('cleanup');
+ * ```
+ *
+ * @param callable $onFulfilledOrRejected
+ * @return ExtendedPromiseInterface
+ */
+ public function always(callable $onFulfilledOrRejected);
+
+ /**
+ * Registers a handler for progress updates from promise. It is a shortcut for:
+ *
+ * ```php
+ * $promise->then(null, null, $onProgress);
+ * ```
+ *
+ * @param callable $onProgress
+ * @return ExtendedPromiseInterface
+ * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore.
+ */
+ public function progress(callable $onProgress);
+}
diff --git a/vendor/react/promise/src/FulfilledPromise.php b/vendor/react/promise/src/FulfilledPromise.php
new file mode 100644
index 0000000..1472752
--- /dev/null
+++ b/vendor/react/promise/src/FulfilledPromise.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace React\Promise;
+
+/**
+ * @deprecated 2.8.0 External usage of FulfilledPromise is deprecated, use `resolve()` instead.
+ */
+class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
+{
+ private $value;
+
+ public function __construct($value = null)
+ {
+ if ($value instanceof PromiseInterface) {
+ throw new \InvalidArgumentException('You cannot create React\Promise\FulfilledPromise with a promise. Use React\Promise\resolve($promiseOrValue) instead.');
+ }
+
+ $this->value = $value;
+ }
+
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null === $onFulfilled) {
+ return $this;
+ }
+
+ try {
+ return resolve($onFulfilled($this->value));
+ } catch (\Throwable $exception) {
+ return new RejectedPromise($exception);
+ } catch (\Exception $exception) {
+ return new RejectedPromise($exception);
+ }
+ }
+
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null === $onFulfilled) {
+ return;
+ }
+
+ $result = $onFulfilled($this->value);
+
+ if ($result instanceof ExtendedPromiseInterface) {
+ $result->done();
+ }
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this;
+ }
+
+ public function always(callable $onFulfilledOrRejected)
+ {
+ return $this->then(function ($value) use ($onFulfilledOrRejected) {
+ return resolve($onFulfilledOrRejected())->then(function () use ($value) {
+ return $value;
+ });
+ });
+ }
+
+ public function progress(callable $onProgress)
+ {
+ return $this;
+ }
+
+ public function cancel()
+ {
+ }
+}
diff --git a/vendor/react/promise/src/LazyPromise.php b/vendor/react/promise/src/LazyPromise.php
new file mode 100644
index 0000000..bbe9293
--- /dev/null
+++ b/vendor/react/promise/src/LazyPromise.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace React\Promise;
+
+/**
+ * @deprecated 2.8.0 LazyPromise is deprecated and should not be used anymore.
+ */
+class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
+{
+ private $factory;
+ private $promise;
+
+ public function __construct(callable $factory)
+ {
+ $this->factory = $factory;
+ }
+
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
+ }
+
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ return $this->promise()->done($onFulfilled, $onRejected, $onProgress);
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->promise()->otherwise($onRejected);
+ }
+
+ public function always(callable $onFulfilledOrRejected)
+ {
+ return $this->promise()->always($onFulfilledOrRejected);
+ }
+
+ public function progress(callable $onProgress)
+ {
+ return $this->promise()->progress($onProgress);
+ }
+
+ public function cancel()
+ {
+ return $this->promise()->cancel();
+ }
+
+ /**
+ * @internal
+ * @see Promise::settle()
+ */
+ public function promise()
+ {
+ if (null === $this->promise) {
+ try {
+ $this->promise = resolve(\call_user_func($this->factory));
+ } catch (\Throwable $exception) {
+ $this->promise = new RejectedPromise($exception);
+ } catch (\Exception $exception) {
+ $this->promise = new RejectedPromise($exception);
+ }
+ }
+
+ return $this->promise;
+ }
+}
diff --git a/vendor/react/promise/src/Promise.php b/vendor/react/promise/src/Promise.php
new file mode 100644
index 0000000..33759e6
--- /dev/null
+++ b/vendor/react/promise/src/Promise.php
@@ -0,0 +1,256 @@
+<?php
+
+namespace React\Promise;
+
+class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
+{
+ private $canceller;
+ private $result;
+
+ private $handlers = [];
+ private $progressHandlers = [];
+
+ private $requiredCancelRequests = 0;
+ private $cancelRequests = 0;
+
+ public function __construct(callable $resolver, callable $canceller = null)
+ {
+ $this->canceller = $canceller;
+
+ // Explicitly overwrite arguments with null values before invoking
+ // resolver function. This ensure that these arguments do not show up
+ // in the stack trace in PHP 7+ only.
+ $cb = $resolver;
+ $resolver = $canceller = null;
+ $this->call($cb);
+ }
+
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null !== $this->result) {
+ return $this->result->then($onFulfilled, $onRejected, $onProgress);
+ }
+
+ if (null === $this->canceller) {
+ return new static($this->resolver($onFulfilled, $onRejected, $onProgress));
+ }
+
+ // This promise has a canceller, so we create a new child promise which
+ // has a canceller that invokes the parent canceller if all other
+ // followers are also cancelled. We keep a reference to this promise
+ // instance for the static canceller function and clear this to avoid
+ // keeping a cyclic reference between parent and follower.
+ $parent = $this;
+ ++$parent->requiredCancelRequests;
+
+ return new static(
+ $this->resolver($onFulfilled, $onRejected, $onProgress),
+ static function () use (&$parent) {
+ if (++$parent->cancelRequests >= $parent->requiredCancelRequests) {
+ $parent->cancel();
+ }
+
+ $parent = null;
+ }
+ );
+ }
+
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null !== $this->result) {
+ return $this->result->done($onFulfilled, $onRejected, $onProgress);
+ }
+
+ $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) {
+ $promise
+ ->done($onFulfilled, $onRejected);
+ };
+
+ if ($onProgress) {
+ $this->progressHandlers[] = $onProgress;
+ }
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, static function ($reason) use ($onRejected) {
+ if (!_checkTypehint($onRejected, $reason)) {
+ return new RejectedPromise($reason);
+ }
+
+ return $onRejected($reason);
+ });
+ }
+
+ public function always(callable $onFulfilledOrRejected)
+ {
+ return $this->then(static function ($value) use ($onFulfilledOrRejected) {
+ return resolve($onFulfilledOrRejected())->then(function () use ($value) {
+ return $value;
+ });
+ }, static function ($reason) use ($onFulfilledOrRejected) {
+ return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
+ return new RejectedPromise($reason);
+ });
+ });
+ }
+
+ public function progress(callable $onProgress)
+ {
+ return $this->then(null, null, $onProgress);
+ }
+
+ public function cancel()
+ {
+ if (null === $this->canceller || null !== $this->result) {
+ return;
+ }
+
+ $canceller = $this->canceller;
+ $this->canceller = null;
+
+ $this->call($canceller);
+ }
+
+ private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) {
+ if ($onProgress) {
+ $progressHandler = static function ($update) use ($notify, $onProgress) {
+ try {
+ $notify($onProgress($update));
+ } catch (\Throwable $e) {
+ $notify($e);
+ } catch (\Exception $e) {
+ $notify($e);
+ }
+ };
+ } else {
+ $progressHandler = $notify;
+ }
+
+ $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
+ $promise
+ ->then($onFulfilled, $onRejected)
+ ->done($resolve, $reject, $progressHandler);
+ };
+
+ $this->progressHandlers[] = $progressHandler;
+ };
+ }
+
+ private function reject($reason = null)
+ {
+ if (null !== $this->result) {
+ return;
+ }
+
+ $this->settle(reject($reason));
+ }
+
+ private function settle(ExtendedPromiseInterface $promise)
+ {
+ $promise = $this->unwrap($promise);
+
+ if ($promise === $this) {
+ $promise = new RejectedPromise(
+ new \LogicException('Cannot resolve a promise with itself.')
+ );
+ }
+
+ $handlers = $this->handlers;
+
+ $this->progressHandlers = $this->handlers = [];
+ $this->result = $promise;
+ $this->canceller = null;
+
+ foreach ($handlers as $handler) {
+ $handler($promise);
+ }
+ }
+
+ private function unwrap($promise)
+ {
+ $promise = $this->extract($promise);
+
+ while ($promise instanceof self && null !== $promise->result) {
+ $promise = $this->extract($promise->result);
+ }
+
+ return $promise;
+ }
+
+ private function extract($promise)
+ {
+ if ($promise instanceof LazyPromise) {
+ $promise = $promise->promise();
+ }
+
+ return $promise;
+ }
+
+ private function call(callable $cb)
+ {
+ // Explicitly overwrite argument with null value. This ensure that this
+ // argument does not show up in the stack trace in PHP 7+ only.
+ $callback = $cb;
+ $cb = null;
+
+ // Use reflection to inspect number of arguments expected by this callback.
+ // We did some careful benchmarking here: Using reflection to avoid unneeded
+ // function arguments is actually faster than blindly passing them.
+ // Also, this helps avoiding unnecessary function arguments in the call stack
+ // if the callback creates an Exception (creating garbage cycles).
+ if (\is_array($callback)) {
+ $ref = new \ReflectionMethod($callback[0], $callback[1]);
+ } elseif (\is_object($callback) && !$callback instanceof \Closure) {
+ $ref = new \ReflectionMethod($callback, '__invoke');
+ } else {
+ $ref = new \ReflectionFunction($callback);
+ }
+ $args = $ref->getNumberOfParameters();
+
+ try {
+ if ($args === 0) {
+ $callback();
+ } else {
+ // Keep references to this promise instance for the static resolve/reject functions.
+ // By using static callbacks that are not bound to this instance
+ // and passing the target promise instance by reference, we can
+ // still execute its resolving logic and still clear this
+ // reference when settling the promise. This helps avoiding
+ // garbage cycles if any callback creates an Exception.
+ // These assumptions are covered by the test suite, so if you ever feel like
+ // refactoring this, go ahead, any alternative suggestions are welcome!
+ $target =& $this;
+ $progressHandlers =& $this->progressHandlers;
+
+ $callback(
+ static function ($value = null) use (&$target) {
+ if ($target !== null) {
+ $target->settle(resolve($value));
+ $target = null;
+ }
+ },
+ static function ($reason = null) use (&$target) {
+ if ($target !== null) {
+ $target->reject($reason);
+ $target = null;
+ }
+ },
+ static function ($update = null) use (&$progressHandlers) {
+ foreach ($progressHandlers as $handler) {
+ $handler($update);
+ }
+ }
+ );
+ }
+ } catch (\Throwable $e) {
+ $target = null;
+ $this->reject($e);
+ } catch (\Exception $e) {
+ $target = null;
+ $this->reject($e);
+ }
+ }
+}
diff --git a/vendor/react/promise/src/PromiseInterface.php b/vendor/react/promise/src/PromiseInterface.php
new file mode 100644
index 0000000..edcb007
--- /dev/null
+++ b/vendor/react/promise/src/PromiseInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace React\Promise;
+
+interface PromiseInterface
+{
+ /**
+ * Transforms a promise's value by applying a function to the promise's fulfillment
+ * or rejection value. Returns a new promise for the transformed result.
+ *
+ * The `then()` method registers new fulfilled and rejection handlers with a promise
+ * (all parameters are optional):
+ *
+ * * `$onFulfilled` will be invoked once the promise is fulfilled and passed
+ * the result as the first argument.
+ * * `$onRejected` will be invoked once the promise is rejected and passed the
+ * reason as the first argument.
+ * * `$onProgress` (deprecated) will be invoked whenever the producer of the promise
+ * triggers progress notifications and passed a single argument (whatever it
+ * wants) to indicate progress.
+ *
+ * It returns a new promise that will fulfill with the return value of either
+ * `$onFulfilled` or `$onRejected`, whichever is called, or will reject with
+ * the thrown exception if either throws.
+ *
+ * A promise makes the following guarantees about handlers registered in
+ * the same call to `then()`:
+ *
+ * 1. Only one of `$onFulfilled` or `$onRejected` will be called,
+ * never both.
+ * 2. `$onFulfilled` and `$onRejected` will never be called more
+ * than once.
+ * 3. `$onProgress` (deprecated) may be called multiple times.
+ *
+ * @param callable|null $onFulfilled
+ * @param callable|null $onRejected
+ * @param callable|null $onProgress This argument is deprecated and should not be used anymore.
+ * @return PromiseInterface
+ */
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
+}
diff --git a/vendor/react/promise/src/PromisorInterface.php b/vendor/react/promise/src/PromisorInterface.php
new file mode 100644
index 0000000..bd64400
--- /dev/null
+++ b/vendor/react/promise/src/PromisorInterface.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace React\Promise;
+
+interface PromisorInterface
+{
+ /**
+ * Returns the promise of the deferred.
+ *
+ * @return PromiseInterface
+ */
+ public function promise();
+}
diff --git a/vendor/react/promise/src/RejectedPromise.php b/vendor/react/promise/src/RejectedPromise.php
new file mode 100644
index 0000000..09cd4ab
--- /dev/null
+++ b/vendor/react/promise/src/RejectedPromise.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace React\Promise;
+
+/**
+ * @deprecated 2.8.0 External usage of RejectedPromise is deprecated, use `reject()` instead.
+ */
+class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
+{
+ private $reason;
+
+ public function __construct($reason = null)
+ {
+ if ($reason instanceof PromiseInterface) {
+ throw new \InvalidArgumentException('You cannot create React\Promise\RejectedPromise with a promise. Use React\Promise\reject($promiseOrValue) instead.');
+ }
+
+ $this->reason = $reason;
+ }
+
+ public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null === $onRejected) {
+ return $this;
+ }
+
+ try {
+ return resolve($onRejected($this->reason));
+ } catch (\Throwable $exception) {
+ return new RejectedPromise($exception);
+ } catch (\Exception $exception) {
+ return new RejectedPromise($exception);
+ }
+ }
+
+ public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
+ {
+ if (null === $onRejected) {
+ throw UnhandledRejectionException::resolve($this->reason);
+ }
+
+ $result = $onRejected($this->reason);
+
+ if ($result instanceof self) {
+ throw UnhandledRejectionException::resolve($result->reason);
+ }
+
+ if ($result instanceof ExtendedPromiseInterface) {
+ $result->done();
+ }
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ if (!_checkTypehint($onRejected, $this->reason)) {
+ return $this;
+ }
+
+ return $this->then(null, $onRejected);
+ }
+
+ public function always(callable $onFulfilledOrRejected)
+ {
+ return $this->then(null, function ($reason) use ($onFulfilledOrRejected) {
+ return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
+ return new RejectedPromise($reason);
+ });
+ });
+ }
+
+ public function progress(callable $onProgress)
+ {
+ return $this;
+ }
+
+ public function cancel()
+ {
+ }
+}
diff --git a/vendor/react/promise/src/UnhandledRejectionException.php b/vendor/react/promise/src/UnhandledRejectionException.php
new file mode 100644
index 0000000..e7fe2f7
--- /dev/null
+++ b/vendor/react/promise/src/UnhandledRejectionException.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace React\Promise;
+
+class UnhandledRejectionException extends \RuntimeException
+{
+ private $reason;
+
+ public static function resolve($reason)
+ {
+ if ($reason instanceof \Exception || $reason instanceof \Throwable) {
+ return $reason;
+ }
+
+ return new static($reason);
+ }
+
+ public function __construct($reason)
+ {
+ $this->reason = $reason;
+
+ $message = \sprintf('Unhandled Rejection: %s', \json_encode($reason));
+
+ parent::__construct($message, 0);
+ }
+
+ public function getReason()
+ {
+ return $this->reason;
+ }
+}
diff --git a/vendor/react/promise/src/functions.php b/vendor/react/promise/src/functions.php
new file mode 100644
index 0000000..429f0e7
--- /dev/null
+++ b/vendor/react/promise/src/functions.php
@@ -0,0 +1,407 @@
+<?php
+
+namespace React\Promise;
+
+/**
+ * Creates a promise for the supplied `$promiseOrValue`.
+ *
+ * If `$promiseOrValue` is a value, it will be the resolution value of the
+ * returned promise.
+ *
+ * If `$promiseOrValue` is a thenable (any object that provides a `then()` method),
+ * a trusted promise that follows the state of the thenable is returned.
+ *
+ * If `$promiseOrValue` is a promise, it will be returned as is.
+ *
+ * @param mixed $promiseOrValue
+ * @return PromiseInterface
+ */
+function resolve($promiseOrValue = null)
+{
+ if ($promiseOrValue instanceof ExtendedPromiseInterface) {
+ return $promiseOrValue;
+ }
+
+ // Check is_object() first to avoid method_exists() triggering
+ // class autoloaders if $promiseOrValue is a string.
+ if (\is_object($promiseOrValue) && \method_exists($promiseOrValue, 'then')) {
+ $canceller = null;
+
+ if (\method_exists($promiseOrValue, 'cancel')) {
+ $canceller = [$promiseOrValue, 'cancel'];
+ }
+
+ return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) {
+ $promiseOrValue->then($resolve, $reject, $notify);
+ }, $canceller);
+ }
+
+ return new FulfilledPromise($promiseOrValue);
+}
+
+/**
+ * Creates a rejected promise for the supplied `$promiseOrValue`.
+ *
+ * If `$promiseOrValue` is a value, it will be the rejection value of the
+ * returned promise.
+ *
+ * If `$promiseOrValue` is a promise, its completion value will be the rejected
+ * value of the returned promise.
+ *
+ * This can be useful in situations where you need to reject a promise without
+ * throwing an exception. For example, it allows you to propagate a rejection with
+ * the value of another promise.
+ *
+ * @param mixed $promiseOrValue
+ * @return PromiseInterface
+ */
+function reject($promiseOrValue = null)
+{
+ if ($promiseOrValue instanceof PromiseInterface) {
+ return resolve($promiseOrValue)->then(function ($value) {
+ return new RejectedPromise($value);
+ });
+ }
+
+ return new RejectedPromise($promiseOrValue);
+}
+
+/**
+ * Returns a promise that will resolve only once all the items in
+ * `$promisesOrValues` have resolved. The resolution value of the returned promise
+ * will be an array containing the resolution values of each of the items in
+ * `$promisesOrValues`.
+ *
+ * @param array $promisesOrValues
+ * @return PromiseInterface
+ */
+function all($promisesOrValues)
+{
+ return map($promisesOrValues, function ($val) {
+ return $val;
+ });
+}
+
+/**
+ * Initiates a competitive race that allows one winner. Returns a promise which is
+ * resolved in the same way the first settled promise resolves.
+ *
+ * The returned promise will become **infinitely pending** if `$promisesOrValues`
+ * contains 0 items.
+ *
+ * @param array $promisesOrValues
+ * @return PromiseInterface
+ */
+function race($promisesOrValues)
+{
+ $cancellationQueue = new CancellationQueue();
+ $cancellationQueue->enqueue($promisesOrValues);
+
+ return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) {
+ resolve($promisesOrValues)
+ ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) {
+ if (!is_array($array) || !$array) {
+ $resolve();
+ return;
+ }
+
+ foreach ($array as $promiseOrValue) {
+ $cancellationQueue->enqueue($promiseOrValue);
+
+ resolve($promiseOrValue)
+ ->done($resolve, $reject, $notify);
+ }
+ }, $reject, $notify);
+ }, $cancellationQueue);
+}
+
+/**
+ * Returns a promise that will resolve when any one of the items in
+ * `$promisesOrValues` resolves. The resolution value of the returned promise
+ * will be the resolution value of the triggering item.
+ *
+ * The returned promise will only reject if *all* items in `$promisesOrValues` are
+ * rejected. The rejection value will be an array of all rejection reasons.
+ *
+ * The returned promise will also reject with a `React\Promise\Exception\LengthException`
+ * if `$promisesOrValues` contains 0 items.
+ *
+ * @param array $promisesOrValues
+ * @return PromiseInterface
+ */
+function any($promisesOrValues)
+{
+ return some($promisesOrValues, 1)
+ ->then(function ($val) {
+ return \array_shift($val);
+ });
+}
+
+/**
+ * Returns a promise that will resolve when `$howMany` of the supplied items in
+ * `$promisesOrValues` resolve. The resolution value of the returned promise
+ * will be an array of length `$howMany` containing the resolution values of the
+ * triggering items.
+ *
+ * The returned promise will reject if it becomes impossible for `$howMany` items
+ * to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items
+ * reject). The rejection value will be an array of
+ * `(count($promisesOrValues) - $howMany) + 1` rejection reasons.
+ *
+ * The returned promise will also reject with a `React\Promise\Exception\LengthException`
+ * if `$promisesOrValues` contains less items than `$howMany`.
+ *
+ * @param array $promisesOrValues
+ * @param int $howMany
+ * @return PromiseInterface
+ */
+function some($promisesOrValues, $howMany)
+{
+ $cancellationQueue = new CancellationQueue();
+ $cancellationQueue->enqueue($promisesOrValues);
+
+ return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) {
+ resolve($promisesOrValues)
+ ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) {
+ if (!\is_array($array) || $howMany < 1) {
+ $resolve([]);
+ return;
+ }
+
+ $len = \count($array);
+
+ if ($len < $howMany) {
+ throw new Exception\LengthException(
+ \sprintf(
+ 'Input array must contain at least %d item%s but contains only %s item%s.',
+ $howMany,
+ 1 === $howMany ? '' : 's',
+ $len,
+ 1 === $len ? '' : 's'
+ )
+ );
+ }
+
+ $toResolve = $howMany;
+ $toReject = ($len - $toResolve) + 1;
+ $values = [];
+ $reasons = [];
+
+ foreach ($array as $i => $promiseOrValue) {
+ $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) {
+ if ($toResolve < 1 || $toReject < 1) {
+ return;
+ }
+
+ $values[$i] = $val;
+
+ if (0 === --$toResolve) {
+ $resolve($values);
+ }
+ };
+
+ $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) {
+ if ($toResolve < 1 || $toReject < 1) {
+ return;
+ }
+
+ $reasons[$i] = $reason;
+
+ if (0 === --$toReject) {
+ $reject($reasons);
+ }
+ };
+
+ $cancellationQueue->enqueue($promiseOrValue);
+
+ resolve($promiseOrValue)
+ ->done($fulfiller, $rejecter, $notify);
+ }
+ }, $reject, $notify);
+ }, $cancellationQueue);
+}
+
+/**
+ * Traditional map function, similar to `array_map()`, but allows input to contain
+ * promises and/or values, and `$mapFunc` may return either a value or a promise.
+ *
+ * The map function receives each item as argument, where item is a fully resolved
+ * value of a promise or value in `$promisesOrValues`.
+ *
+ * @param array $promisesOrValues
+ * @param callable $mapFunc
+ * @return PromiseInterface
+ */
+function map($promisesOrValues, callable $mapFunc)
+{
+ $cancellationQueue = new CancellationQueue();
+ $cancellationQueue->enqueue($promisesOrValues);
+
+ return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) {
+ resolve($promisesOrValues)
+ ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) {
+ if (!\is_array($array) || !$array) {
+ $resolve([]);
+ return;
+ }
+
+ $toResolve = \count($array);
+ $values = [];
+
+ foreach ($array as $i => $promiseOrValue) {
+ $cancellationQueue->enqueue($promiseOrValue);
+ $values[$i] = null;
+
+ resolve($promiseOrValue)
+ ->then($mapFunc)
+ ->done(
+ function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
+ $values[$i] = $mapped;
+
+ if (0 === --$toResolve) {
+ $resolve($values);
+ }
+ },
+ $reject,
+ $notify
+ );
+ }
+ }, $reject, $notify);
+ }, $cancellationQueue);
+}
+
+/**
+ * Traditional reduce function, similar to `array_reduce()`, but input may contain
+ * promises and/or values, and `$reduceFunc` may return either a value or a
+ * promise, *and* `$initialValue` may be a promise or a value for the starting
+ * value.
+ *
+ * @param array $promisesOrValues
+ * @param callable $reduceFunc
+ * @param mixed $initialValue
+ * @return PromiseInterface
+ */
+function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null)
+{
+ $cancellationQueue = new CancellationQueue();
+ $cancellationQueue->enqueue($promisesOrValues);
+
+ return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) {
+ resolve($promisesOrValues)
+ ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) {
+ if (!\is_array($array)) {
+ $array = [];
+ }
+
+ $total = \count($array);
+ $i = 0;
+
+ // Wrap the supplied $reduceFunc with one that handles promises and then
+ // delegates to the supplied.
+ $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) {
+ $cancellationQueue->enqueue($val);
+
+ return $current
+ ->then(function ($c) use ($reduceFunc, $total, &$i, $val) {
+ return resolve($val)
+ ->then(function ($value) use ($reduceFunc, $total, &$i, $c) {
+ return $reduceFunc($c, $value, $i++, $total);
+ });
+ });
+ };
+
+ $cancellationQueue->enqueue($initialValue);
+
+ \array_reduce($array, $wrappedReduceFunc, resolve($initialValue))
+ ->done($resolve, $reject, $notify);
+ }, $reject, $notify);
+ }, $cancellationQueue);
+}
+
+/**
+ * @internal
+ */
+function _checkTypehint(callable $callback, $object)
+{
+ if (!\is_object($object)) {
+ return true;
+ }
+
+ if (\is_array($callback)) {
+ $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
+ } elseif (\is_object($callback) && !$callback instanceof \Closure) {
+ $callbackReflection = new \ReflectionMethod($callback, '__invoke');
+ } else {
+ $callbackReflection = new \ReflectionFunction($callback);
+ }
+
+ $parameters = $callbackReflection->getParameters();
+
+ if (!isset($parameters[0])) {
+ return true;
+ }
+
+ $expectedException = $parameters[0];
+
+ // PHP before v8 used an easy API:
+ if (\PHP_VERSION_ID < 70100 || \defined('HHVM_VERSION')) {
+ if (!$expectedException->getClass()) {
+ return true;
+ }
+
+ return $expectedException->getClass()->isInstance($object);
+ }
+
+ // Extract the type of the argument and handle different possibilities
+ $type = $expectedException->getType();
+
+ $isTypeUnion = true;
+ $types = [];
+
+ switch (true) {
+ case $type === null:
+ break;
+ case $type instanceof \ReflectionNamedType:
+ $types = [$type];
+ break;
+ case $type instanceof \ReflectionIntersectionType:
+ $isTypeUnion = false;
+ case $type instanceof \ReflectionUnionType;
+ $types = $type->getTypes();
+ break;
+ default:
+ throw new \LogicException('Unexpected return value of ReflectionParameter::getType');
+ }
+
+ // If there is no type restriction, it matches
+ if (empty($types)) {
+ return true;
+ }
+
+ foreach ($types as $type) {
+ if (!$type instanceof \ReflectionNamedType) {
+ throw new \LogicException('This implementation does not support groups of intersection or union types');
+ }
+
+ // A named-type can be either a class-name or a built-in type like string, int, array, etc.
+ $matches = ($type->isBuiltin() && \gettype($object) === $type->getName())
+ || (new \ReflectionClass($type->getName()))->isInstance($object);
+
+
+ // If we look for a single match (union), we can return early on match
+ // If we look for a full match (intersection), we can return early on mismatch
+ if ($matches) {
+ if ($isTypeUnion) {
+ return true;
+ }
+ } else {
+ if (!$isTypeUnion) {
+ return false;
+ }
+ }
+ }
+
+ // If we look for a single match (union) and did not return early, we matched no type and are false
+ // If we look for a full match (intersection) and did not return early, we matched all types and are true
+ return $isTypeUnion ? false : true;
+}
diff --git a/vendor/react/promise/src/functions_include.php b/vendor/react/promise/src/functions_include.php
new file mode 100644
index 0000000..bd0c54f
--- /dev/null
+++ b/vendor/react/promise/src/functions_include.php
@@ -0,0 +1,5 @@
+<?php
+
+if (!\function_exists('React\Promise\resolve')) {
+ require __DIR__.'/functions.php';
+}
diff --git a/vendor/react/socket/LICENSE b/vendor/react/socket/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/socket/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/socket/composer.json b/vendor/react/socket/composer.json
new file mode 100644
index 0000000..ec50942
--- /dev/null
+++ b/vendor/react/socket/composer.json
@@ -0,0 +1,52 @@
+{
+ "name": "react/socket",
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": ["async", "socket", "stream", "connection", "ReactPHP"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "react/dns": "^1.8",
+ "react/event-loop": "^1.2",
+ "react/promise": "^2.6.0 || ^1.2.1",
+ "react/promise-timer": "^1.8",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/promise-stream": "^1.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Tests\\Socket\\": "tests"
+ }
+ }
+}
diff --git a/vendor/react/socket/src/Connection.php b/vendor/react/socket/src/Connection.php
new file mode 100644
index 0000000..5e3b00d
--- /dev/null
+++ b/vendor/react/socket/src/Connection.php
@@ -0,0 +1,187 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\LoopInterface;
+use React\Stream\DuplexResourceStream;
+use React\Stream\Util;
+use React\Stream\WritableResourceStream;
+use React\Stream\WritableStreamInterface;
+
+/**
+ * The actual connection implementation for ConnectionInterface
+ *
+ * This class should only be used internally, see ConnectionInterface instead.
+ *
+ * @see ConnectionInterface
+ * @internal
+ */
+class Connection extends EventEmitter implements ConnectionInterface
+{
+ /**
+ * Internal flag whether this is a Unix domain socket (UDS) connection
+ *
+ * @internal
+ */
+ public $unix = false;
+
+ /**
+ * Internal flag whether encryption has been enabled on this connection
+ *
+ * Mostly used by internal StreamEncryption so that connection returns
+ * `tls://` scheme for encrypted connections instead of `tcp://`.
+ *
+ * @internal
+ */
+ public $encryptionEnabled = false;
+
+ /** @internal */
+ public $stream;
+
+ private $input;
+
+ public function __construct($resource, LoopInterface $loop)
+ {
+ // PHP < 7.3.3 (and PHP < 7.2.15) suffers from a bug where feof() might
+ // block with 100% CPU usage on fragmented TLS records.
+ // We try to work around this by always consuming the complete receive
+ // buffer at once to avoid stale data in TLS buffers. This is known to
+ // work around high CPU usage for well-behaving peers, but this may
+ // cause very large data chunks for high throughput scenarios. The buggy
+ // behavior can still be triggered due to network I/O buffers or
+ // malicious peers on affected versions, upgrading is highly recommended.
+ // @link https://bugs.php.net/bug.php?id=77390
+ $clearCompleteBuffer = \PHP_VERSION_ID < 70215 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70303);
+
+ // PHP < 7.1.4 (and PHP < 7.0.18) suffers from a bug when writing big
+ // chunks of data over TLS streams at once.
+ // We try to work around this by limiting the write chunk size to 8192
+ // bytes for older PHP versions only.
+ // This is only a work-around and has a noticable performance penalty on
+ // affected versions. Please update your PHP version.
+ // This applies to all streams because TLS may be enabled later on.
+ // See https://github.com/reactphp/socket/issues/105
+ $limitWriteChunks = (\PHP_VERSION_ID < 70018 || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70104));
+
+ $this->input = new DuplexResourceStream(
+ $resource,
+ $loop,
+ $clearCompleteBuffer ? -1 : null,
+ new WritableResourceStream($resource, $loop, null, $limitWriteChunks ? 8192 : null)
+ );
+
+ $this->stream = $resource;
+
+ Util::forwardEvents($this->input, $this, array('data', 'end', 'error', 'close', 'pipe', 'drain'));
+
+ $this->input->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return $this->input->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->input->isWritable();
+ }
+
+ public function pause()
+ {
+ $this->input->pause();
+ }
+
+ public function resume()
+ {
+ $this->input->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return $this->input->pipe($dest, $options);
+ }
+
+ public function write($data)
+ {
+ return $this->input->write($data);
+ }
+
+ public function end($data = null)
+ {
+ $this->input->end($data);
+ }
+
+ public function close()
+ {
+ $this->input->close();
+ $this->handleClose();
+ $this->removeAllListeners();
+ }
+
+ public function handleClose()
+ {
+ if (!\is_resource($this->stream)) {
+ return;
+ }
+
+ // Try to cleanly shut down socket and ignore any errors in case other
+ // side already closed. Shutting down may return to blocking mode on
+ // some legacy versions, so reset to non-blocking just in case before
+ // continuing to close the socket resource.
+ // Underlying Stream implementation will take care of closing file
+ // handle, so we otherwise keep this open here.
+ @\stream_socket_shutdown($this->stream, \STREAM_SHUT_RDWR);
+ \stream_set_blocking($this->stream, false);
+ }
+
+ public function getRemoteAddress()
+ {
+ if (!\is_resource($this->stream)) {
+ return null;
+ }
+
+ return $this->parseAddress(\stream_socket_get_name($this->stream, true));
+ }
+
+ public function getLocalAddress()
+ {
+ if (!\is_resource($this->stream)) {
+ return null;
+ }
+
+ return $this->parseAddress(\stream_socket_get_name($this->stream, false));
+ }
+
+ private function parseAddress($address)
+ {
+ if ($address === false) {
+ return null;
+ }
+
+ if ($this->unix) {
+ // remove trailing colon from address for HHVM < 3.19: https://3v4l.org/5C1lo
+ // note that technically ":" is a valid address, so keep this in place otherwise
+ if (\substr($address, -1) === ':' && \defined('HHVM_VERSION_ID') && \HHVM_VERSION_ID < 31900) {
+ $address = (string)\substr($address, 0, -1); // @codeCoverageIgnore
+ }
+
+ // work around unknown addresses should return null value: https://3v4l.org/5C1lo and https://bugs.php.net/bug.php?id=74556
+ // PHP uses "\0" string and HHVM uses empty string (colon removed above)
+ if ($address === '' || $address[0] === "\x00" ) {
+ return null; // @codeCoverageIgnore
+ }
+
+ return 'unix://' . $address;
+ }
+
+ // check if this is an IPv6 address which includes multiple colons but no square brackets
+ $pos = \strrpos($address, ':');
+ if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
+ $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1); // @codeCoverageIgnore
+ }
+
+ return ($this->encryptionEnabled ? 'tls' : 'tcp') . '://' . $address;
+ }
+}
diff --git a/vendor/react/socket/src/ConnectionInterface.php b/vendor/react/socket/src/ConnectionInterface.php
new file mode 100644
index 0000000..64613b5
--- /dev/null
+++ b/vendor/react/socket/src/ConnectionInterface.php
@@ -0,0 +1,119 @@
+<?php
+
+namespace React\Socket;
+
+use React\Stream\DuplexStreamInterface;
+
+/**
+ * Any incoming and outgoing connection is represented by this interface,
+ * such as a normal TCP/IP connection.
+ *
+ * An incoming or outgoing connection is a duplex stream (both readable and
+ * writable) that implements React's
+ * [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
+ * It contains additional properties for the local and remote address (client IP)
+ * where this connection has been established to/from.
+ *
+ * Most commonly, instances implementing this `ConnectionInterface` are emitted
+ * by all classes implementing the [`ServerInterface`](#serverinterface) and
+ * used by all classes implementing the [`ConnectorInterface`](#connectorinterface).
+ *
+ * Because the `ConnectionInterface` implements the underlying
+ * [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface)
+ * you can use any of its events and methods as usual:
+ *
+ * ```php
+ * $connection->on('data', function ($chunk) {
+ * echo $chunk;
+ * });
+ *
+ * $connection->on('end', function () {
+ * echo 'ended';
+ * });
+ *
+ * $connection->on('error', function (Exception $e) {
+ * echo 'error: ' . $e->getMessage();
+ * });
+ *
+ * $connection->on('close', function () {
+ * echo 'closed';
+ * });
+ *
+ * $connection->write($data);
+ * $connection->end($data = null);
+ * $connection->close();
+ * // …
+ * ```
+ *
+ * For more details, see the
+ * [`DuplexStreamInterface`](https://github.com/reactphp/stream#duplexstreaminterface).
+ *
+ * @see DuplexStreamInterface
+ * @see ServerInterface
+ * @see ConnectorInterface
+ */
+interface ConnectionInterface extends DuplexStreamInterface
+{
+ /**
+ * Returns the full remote address (URI) where this connection has been established with
+ *
+ * ```php
+ * $address = $connection->getRemoteAddress();
+ * echo 'Connection with ' . $address . PHP_EOL;
+ * ```
+ *
+ * If the remote address can not be determined or is unknown at this time (such as
+ * after the connection has been closed), it MAY return a `NULL` value instead.
+ *
+ * Otherwise, it will return the full address (URI) as a string value, such
+ * as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
+ * `unix://example.sock` or `unix:///path/to/example.sock`.
+ * Note that individual URI components are application specific and depend
+ * on the underlying transport protocol.
+ *
+ * If this is a TCP/IP based connection and you only want the remote IP, you may
+ * use something like this:
+ *
+ * ```php
+ * $address = $connection->getRemoteAddress();
+ * $ip = trim(parse_url($address, PHP_URL_HOST), '[]');
+ * echo 'Connection with ' . $ip . PHP_EOL;
+ * ```
+ *
+ * @return ?string remote address (URI) or null if unknown
+ */
+ public function getRemoteAddress();
+
+ /**
+ * Returns the full local address (full URI with scheme, IP and port) where this connection has been established with
+ *
+ * ```php
+ * $address = $connection->getLocalAddress();
+ * echo 'Connection with ' . $address . PHP_EOL;
+ * ```
+ *
+ * If the local address can not be determined or is unknown at this time (such as
+ * after the connection has been closed), it MAY return a `NULL` value instead.
+ *
+ * Otherwise, it will return the full address (URI) as a string value, such
+ * as `tcp://127.0.0.1:8080`, `tcp://[::1]:80`, `tls://127.0.0.1:443`,
+ * `unix://example.sock` or `unix:///path/to/example.sock`.
+ * Note that individual URI components are application specific and depend
+ * on the underlying transport protocol.
+ *
+ * This method complements the [`getRemoteAddress()`](#getremoteaddress) method,
+ * so they should not be confused.
+ *
+ * If your `TcpServer` instance is listening on multiple interfaces (e.g. using
+ * the address `0.0.0.0`), you can use this method to find out which interface
+ * actually accepted this connection (such as a public or local interface).
+ *
+ * If your system has multiple interfaces (e.g. a WAN and a LAN interface),
+ * you can use this method to find out which interface was actually
+ * used for this connection.
+ *
+ * @return ?string local address (URI) or null if unknown
+ * @see self::getRemoteAddress()
+ */
+ public function getLocalAddress();
+}
diff --git a/vendor/react/socket/src/Connector.php b/vendor/react/socket/src/Connector.php
new file mode 100644
index 0000000..93477bd
--- /dev/null
+++ b/vendor/react/socket/src/Connector.php
@@ -0,0 +1,236 @@
+<?php
+
+namespace React\Socket;
+
+use React\Dns\Config\Config as DnsConfig;
+use React\Dns\Resolver\Factory as DnsFactory;
+use React\Dns\Resolver\ResolverInterface;
+use React\EventLoop\LoopInterface;
+
+/**
+ * The `Connector` class is the main class in this package that implements the
+ * `ConnectorInterface` and allows you to create streaming connections.
+ *
+ * You can use this connector to create any kind of streaming connections, such
+ * as plaintext TCP/IP, secure TLS or local Unix connection streams.
+ *
+ * Under the hood, the `Connector` is implemented as a *higher-level facade*
+ * for the lower-level connectors implemented in this package. This means it
+ * also shares all of their features and implementation details.
+ * If you want to typehint in your higher-level protocol implementation, you SHOULD
+ * use the generic [`ConnectorInterface`](#connectorinterface) instead.
+ *
+ * @see ConnectorInterface for the base interface
+ */
+final class Connector implements ConnectorInterface
+{
+ private $connectors = array();
+
+ /**
+ * Instantiate new `Connector`
+ *
+ * ```php
+ * $connector = new React\Socket\Connector();
+ * ```
+ *
+ * This class takes two optional arguments for more advanced usage:
+ *
+ * ```php
+ * // constructor signature as of v1.9.0
+ * $connector = new React\Socket\Connector(array $context = [], ?LoopInterface $loop = null);
+ *
+ * // legacy constructor signature before v1.9.0
+ * $connector = new React\Socket\Connector(?LoopInterface $loop = null, array $context = []);
+ * ```
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param array|LoopInterface|null $context
+ * @param null|LoopInterface|array $loop
+ * @throws \InvalidArgumentException for invalid arguments
+ */
+ public function __construct($context = array(), $loop = null)
+ {
+ // swap arguments for legacy constructor signature
+ if (($context instanceof LoopInterface || $context === null) && (\func_num_args() <= 1 || \is_array($loop))) {
+ $swap = $loop === null ? array(): $loop;
+ $loop = $context;
+ $context = $swap;
+ }
+
+ if (!\is_array($context) || ($loop !== null && !$loop instanceof LoopInterface)) {
+ throw new \InvalidArgumentException('Expected "array $context" and "?LoopInterface $loop" arguments');
+ }
+
+ // apply default options if not explicitly given
+ $context += array(
+ 'tcp' => true,
+ 'tls' => true,
+ 'unix' => true,
+
+ 'dns' => true,
+ 'timeout' => true,
+ 'happy_eyeballs' => true,
+ );
+
+ if ($context['timeout'] === true) {
+ $context['timeout'] = (float)\ini_get("default_socket_timeout");
+ }
+
+ if ($context['tcp'] instanceof ConnectorInterface) {
+ $tcp = $context['tcp'];
+ } else {
+ $tcp = new TcpConnector(
+ $loop,
+ \is_array($context['tcp']) ? $context['tcp'] : array()
+ );
+ }
+
+ if ($context['dns'] !== false) {
+ if ($context['dns'] instanceof ResolverInterface) {
+ $resolver = $context['dns'];
+ } else {
+ if ($context['dns'] !== true) {
+ $config = $context['dns'];
+ } else {
+ // try to load nameservers from system config or default to Google's public DNS
+ $config = DnsConfig::loadSystemConfigBlocking();
+ if (!$config->nameservers) {
+ $config->nameservers[] = '8.8.8.8'; // @codeCoverageIgnore
+ }
+ }
+
+ $factory = new DnsFactory();
+ $resolver = $factory->createCached(
+ $config,
+ $loop
+ );
+ }
+
+ if ($context['happy_eyeballs'] === true) {
+ $tcp = new HappyEyeBallsConnector($loop, $tcp, $resolver);
+ } else {
+ $tcp = new DnsConnector($tcp, $resolver);
+ }
+ }
+
+ if ($context['tcp'] !== false) {
+ $context['tcp'] = $tcp;
+
+ if ($context['timeout'] !== false) {
+ $context['tcp'] = new TimeoutConnector(
+ $context['tcp'],
+ $context['timeout'],
+ $loop
+ );
+ }
+
+ $this->connectors['tcp'] = $context['tcp'];
+ }
+
+ if ($context['tls'] !== false) {
+ if (!$context['tls'] instanceof ConnectorInterface) {
+ $context['tls'] = new SecureConnector(
+ $tcp,
+ $loop,
+ \is_array($context['tls']) ? $context['tls'] : array()
+ );
+ }
+
+ if ($context['timeout'] !== false) {
+ $context['tls'] = new TimeoutConnector(
+ $context['tls'],
+ $context['timeout'],
+ $loop
+ );
+ }
+
+ $this->connectors['tls'] = $context['tls'];
+ }
+
+ if ($context['unix'] !== false) {
+ if (!$context['unix'] instanceof ConnectorInterface) {
+ $context['unix'] = new UnixConnector($loop);
+ }
+ $this->connectors['unix'] = $context['unix'];
+ }
+ }
+
+ public function connect($uri)
+ {
+ $scheme = 'tcp';
+ if (\strpos($uri, '://') !== false) {
+ $scheme = (string)\substr($uri, 0, \strpos($uri, '://'));
+ }
+
+ if (!isset($this->connectors[$scheme])) {
+ return \React\Promise\reject(new \RuntimeException(
+ 'No connector available for URI scheme "' . $scheme . '" (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ return $this->connectors[$scheme]->connect($uri);
+ }
+
+
+ /**
+ * [internal] Builds on URI from the given URI parts and ip address with original hostname as query
+ *
+ * @param array $parts
+ * @param string $host
+ * @param string $ip
+ * @return string
+ * @internal
+ */
+ public static function uri(array $parts, $host, $ip)
+ {
+ $uri = '';
+
+ // prepend original scheme if known
+ if (isset($parts['scheme'])) {
+ $uri .= $parts['scheme'] . '://';
+ }
+
+ if (\strpos($ip, ':') !== false) {
+ // enclose IPv6 addresses in square brackets before appending port
+ $uri .= '[' . $ip . ']';
+ } else {
+ $uri .= $ip;
+ }
+
+ // append original port if known
+ if (isset($parts['port'])) {
+ $uri .= ':' . $parts['port'];
+ }
+
+ // append orignal path if known
+ if (isset($parts['path'])) {
+ $uri .= $parts['path'];
+ }
+
+ // append original query if known
+ if (isset($parts['query'])) {
+ $uri .= '?' . $parts['query'];
+ }
+
+ // append original hostname as query if resolved via DNS and if
+ // destination URI does not contain "hostname" query param already
+ $args = array();
+ \parse_str(isset($parts['query']) ? $parts['query'] : '', $args);
+ if ($host !== $ip && !isset($args['hostname'])) {
+ $uri .= (isset($parts['query']) ? '&' : '?') . 'hostname=' . \rawurlencode($host);
+ }
+
+ // append original fragment if known
+ if (isset($parts['fragment'])) {
+ $uri .= '#' . $parts['fragment'];
+ }
+
+ return $uri;
+ }
+}
diff --git a/vendor/react/socket/src/ConnectorInterface.php b/vendor/react/socket/src/ConnectorInterface.php
new file mode 100644
index 0000000..3dd78f1
--- /dev/null
+++ b/vendor/react/socket/src/ConnectorInterface.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace React\Socket;
+
+/**
+ * The `ConnectorInterface` is responsible for providing an interface for
+ * establishing streaming connections, such as a normal TCP/IP connection.
+ *
+ * This is the main interface defined in this package and it is used throughout
+ * React's vast ecosystem.
+ *
+ * Most higher-level components (such as HTTP, database or other networking
+ * service clients) accept an instance implementing this interface to create their
+ * TCP/IP connection to the underlying networking service.
+ * This is usually done via dependency injection, so it's fairly simple to actually
+ * swap this implementation against any other implementation of this interface.
+ *
+ * The interface only offers a single `connect()` method.
+ *
+ * @see ConnectionInterface
+ */
+interface ConnectorInterface
+{
+ /**
+ * Creates a streaming connection to the given remote address
+ *
+ * If returns a Promise which either fulfills with a stream implementing
+ * `ConnectionInterface` on success or rejects with an `Exception` if the
+ * connection is not successful.
+ *
+ * ```php
+ * $connector->connect('google.com:443')->then(
+ * function (React\Socket\ConnectionInterface $connection) {
+ * // connection successfully established
+ * },
+ * function (Exception $error) {
+ * // failed to connect due to $error
+ * }
+ * );
+ * ```
+ *
+ * The returned Promise MUST be implemented in such a way that it can be
+ * cancelled when it is still pending. Cancelling a pending promise MUST
+ * reject its value with an Exception. It SHOULD clean up any underlying
+ * resources and references as applicable.
+ *
+ * ```php
+ * $promise = $connector->connect($uri);
+ *
+ * $promise->cancel();
+ * ```
+ *
+ * @param string $uri
+ * @return \React\Promise\PromiseInterface resolves with a stream implementing ConnectionInterface on success or rejects with an Exception on error
+ * @see ConnectionInterface
+ */
+ public function connect($uri);
+}
diff --git a/vendor/react/socket/src/DnsConnector.php b/vendor/react/socket/src/DnsConnector.php
new file mode 100644
index 0000000..27fc8f8
--- /dev/null
+++ b/vendor/react/socket/src/DnsConnector.php
@@ -0,0 +1,117 @@
+<?php
+
+namespace React\Socket;
+
+use React\Dns\Resolver\ResolverInterface;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+final class DnsConnector implements ConnectorInterface
+{
+ private $connector;
+ private $resolver;
+
+ public function __construct(ConnectorInterface $connector, ResolverInterface $resolver)
+ {
+ $this->connector = $connector;
+ $this->resolver = $resolver;
+ }
+
+ public function connect($uri)
+ {
+ $original = $uri;
+ if (\strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ $parts = \parse_url($uri);
+ if (isset($parts['scheme'])) {
+ unset($parts['scheme']);
+ }
+ } else {
+ $parts = \parse_url($uri);
+ }
+
+ if (!$parts || !isset($parts['host'])) {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $original . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ $host = \trim($parts['host'], '[]');
+ $connector = $this->connector;
+
+ // skip DNS lookup / URI manipulation if this URI already contains an IP
+ if (@\inet_pton($host) !== false) {
+ return $connector->connect($original);
+ }
+
+ $promise = $this->resolver->resolve($host);
+ $resolved = null;
+
+ return new Promise\Promise(
+ function ($resolve, $reject) use (&$promise, &$resolved, $uri, $connector, $host, $parts) {
+ // resolve/reject with result of DNS lookup
+ $promise->then(function ($ip) use (&$promise, &$resolved, $uri, $connector, $host, $parts) {
+ $resolved = $ip;
+
+ return $promise = $connector->connect(
+ Connector::uri($parts, $host, $ip)
+ )->then(null, function (\Exception $e) use ($uri) {
+ if ($e instanceof \RuntimeException) {
+ $message = \preg_replace('/^(Connection to [^ ]+)[&?]hostname=[^ &]+/', '$1', $e->getMessage());
+ $e = new \RuntimeException(
+ 'Connection to ' . $uri . ' failed: ' . $message,
+ $e->getCode(),
+ $e
+ );
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as &$one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as &$arg) {
+ if ($arg instanceof \Closure) {
+ $arg = 'Object(' . \get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ }
+
+ throw $e;
+ });
+ }, function ($e) use ($uri, $reject) {
+ $reject(new \RuntimeException('Connection to ' . $uri .' failed during DNS lookup: ' . $e->getMessage(), 0, $e));
+ })->then($resolve, $reject);
+ },
+ function ($_, $reject) use (&$promise, &$resolved, $uri) {
+ // cancellation should reject connection attempt
+ // reject DNS resolution with custom reason, otherwise rely on connection cancellation below
+ if ($resolved === null) {
+ $reject(new \RuntimeException(
+ 'Connection to ' . $uri . ' cancelled during DNS lookup (ECONNABORTED)',
+ \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
+ ));
+ }
+
+ // (try to) cancel pending DNS lookup / connection attempt
+ if ($promise instanceof CancellablePromiseInterface) {
+ // overwrite callback arguments for PHP7+ only, so they do not show
+ // up in the Exception trace and do not cause a possible cyclic reference.
+ $_ = $reject = null;
+
+ $promise->cancel();
+ $promise = null;
+ }
+ }
+ );
+ }
+}
diff --git a/vendor/react/socket/src/FdServer.php b/vendor/react/socket/src/FdServer.php
new file mode 100644
index 0000000..2c7a6c4
--- /dev/null
+++ b/vendor/react/socket/src/FdServer.php
@@ -0,0 +1,212 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+
+/**
+ * [Internal] The `FdServer` class implements the `ServerInterface` and
+ * is responsible for accepting connections from an existing file descriptor.
+ *
+ * ```php
+ * $socket = new React\Socket\FdServer(3);
+ * ```
+ *
+ * Whenever a client connects, it will emit a `connection` event with a connection
+ * instance implementing `ConnectionInterface`:
+ *
+ * ```php
+ * $socket->on('connection', function (ConnectionInterface $connection) {
+ * echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * See also the `ServerInterface` for more details.
+ *
+ * @see ServerInterface
+ * @see ConnectionInterface
+ * @internal
+ */
+final class FdServer extends EventEmitter implements ServerInterface
+{
+ private $master;
+ private $loop;
+ private $unix = false;
+ private $listening = false;
+
+ /**
+ * Creates a socket server and starts listening on the given file descriptor
+ *
+ * This starts accepting new incoming connections on the given file descriptor.
+ * See also the `connection event` documented in the `ServerInterface`
+ * for more details.
+ *
+ * ```php
+ * $socket = new React\Socket\FdServer(3);
+ * ```
+ *
+ * If the given FD is invalid or out of range, it will throw an `InvalidArgumentException`:
+ *
+ * ```php
+ * // throws InvalidArgumentException
+ * $socket = new React\Socket\FdServer(-1);
+ * ```
+ *
+ * If the given FD appears to be valid, but listening on it fails (such as
+ * if the FD does not exist or does not refer to a socket server), it will
+ * throw a `RuntimeException`:
+ *
+ * ```php
+ * // throws RuntimeException because FD does not reference a socket server
+ * $socket = new React\Socket\FdServer(0, $loop);
+ * ```
+ *
+ * Note that these error conditions may vary depending on your system and/or
+ * configuration.
+ * See the exception message and code for more details about the actual error
+ * condition.
+ *
+ * @param int|string $fd FD number such as `3` or as URL in the form of `php://fd/3`
+ * @param ?LoopInterface $loop
+ * @throws \InvalidArgumentException if the listening address is invalid
+ * @throws \RuntimeException if listening on this address fails (already in use etc.)
+ */
+ public function __construct($fd, LoopInterface $loop = null)
+ {
+ if (\preg_match('#^php://fd/(\d+)$#', $fd, $m)) {
+ $fd = (int) $m[1];
+ }
+ if (!\is_int($fd) || $fd < 0 || $fd >= \PHP_INT_MAX) {
+ throw new \InvalidArgumentException(
+ 'Invalid FD number given (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ );
+ }
+
+ $this->loop = $loop ?: Loop::get();
+
+ $this->master = @\fopen('php://fd/' . $fd, 'r+');
+ if (false === $this->master) {
+ // Match errstr from PHP's warning message.
+ // fopen(php://fd/3): Failed to open stream: Error duping file descriptor 3; possibly it doesn't exist: [9]: Bad file descriptor
+ $error = \error_get_last();
+ \preg_match('/\[(\d+)\]: (.*)/', $error['message'], $m);
+ $errno = isset($m[1]) ? (int) $m[1] : 0;
+ $errstr = isset($m[2]) ? $m[2] : $error['message'];
+
+ throw new \RuntimeException(
+ 'Failed to listen on FD ' . $fd . ': ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ );
+ }
+
+ $meta = \stream_get_meta_data($this->master);
+ if (!isset($meta['stream_type']) || $meta['stream_type'] !== 'tcp_socket') {
+ \fclose($this->master);
+
+ $errno = \defined('SOCKET_ENOTSOCK') ? \SOCKET_ENOTSOCK : 88;
+ $errstr = \function_exists('socket_strerror') ? \socket_strerror($errno) : 'Not a socket';
+
+ throw new \RuntimeException(
+ 'Failed to listen on FD ' . $fd . ': ' . $errstr . ' (ENOTSOCK)',
+ $errno
+ );
+ }
+
+ // Socket should not have a peer address if this is a listening socket.
+ // Looks like this work-around is the closest we can get because PHP doesn't expose SO_ACCEPTCONN even with ext-sockets.
+ if (\stream_socket_get_name($this->master, true) !== false) {
+ \fclose($this->master);
+
+ $errno = \defined('SOCKET_EISCONN') ? \SOCKET_EISCONN : 106;
+ $errstr = \function_exists('socket_strerror') ? \socket_strerror($errno) : 'Socket is connected';
+
+ throw new \RuntimeException(
+ 'Failed to listen on FD ' . $fd . ': ' . $errstr . ' (EISCONN)',
+ $errno
+ );
+ }
+
+ // Assume this is a Unix domain socket (UDS) when its listening address doesn't parse as a valid URL with a port.
+ // Looks like this work-around is the closest we can get because PHP doesn't expose SO_DOMAIN even with ext-sockets.
+ $this->unix = \parse_url($this->getAddress(), \PHP_URL_PORT) === false;
+
+ \stream_set_blocking($this->master, false);
+
+ $this->resume();
+ }
+
+ public function getAddress()
+ {
+ if (!\is_resource($this->master)) {
+ return null;
+ }
+
+ $address = \stream_socket_get_name($this->master, false);
+
+ if ($this->unix === true) {
+ return 'unix://' . $address;
+ }
+
+ // check if this is an IPv6 address which includes multiple colons but no square brackets
+ $pos = \strrpos($address, ':');
+ if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
+ $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1); // @codeCoverageIgnore
+ }
+
+ return 'tcp://' . $address;
+ }
+
+ public function pause()
+ {
+ if (!$this->listening) {
+ return;
+ }
+
+ $this->loop->removeReadStream($this->master);
+ $this->listening = false;
+ }
+
+ public function resume()
+ {
+ if ($this->listening || !\is_resource($this->master)) {
+ return;
+ }
+
+ $that = $this;
+ $this->loop->addReadStream($this->master, function ($master) use ($that) {
+ try {
+ $newSocket = SocketServer::accept($master);
+ } catch (\RuntimeException $e) {
+ $that->emit('error', array($e));
+ return;
+ }
+ $that->handleConnection($newSocket);
+ });
+ $this->listening = true;
+ }
+
+ public function close()
+ {
+ if (!\is_resource($this->master)) {
+ return;
+ }
+
+ $this->pause();
+ \fclose($this->master);
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleConnection($socket)
+ {
+ $connection = new Connection($socket, $this->loop);
+ $connection->unix = $this->unix;
+
+ $this->emit('connection', array($connection));
+ }
+}
diff --git a/vendor/react/socket/src/FixedUriConnector.php b/vendor/react/socket/src/FixedUriConnector.php
new file mode 100644
index 0000000..f83241d
--- /dev/null
+++ b/vendor/react/socket/src/FixedUriConnector.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace React\Socket;
+
+/**
+ * Decorates an existing Connector to always use a fixed, preconfigured URI
+ *
+ * This can be useful for consumers that do not support certain URIs, such as
+ * when you want to explicitly connect to a Unix domain socket (UDS) path
+ * instead of connecting to a default address assumed by an higher-level API:
+ *
+ * ```php
+ * $connector = new React\Socket\FixedUriConnector(
+ * 'unix:///var/run/docker.sock',
+ * new React\Socket\UnixConnector()
+ * );
+ *
+ * // destination will be ignored, actually connects to Unix domain socket
+ * $promise = $connector->connect('localhost:80');
+ * ```
+ */
+class FixedUriConnector implements ConnectorInterface
+{
+ private $uri;
+ private $connector;
+
+ /**
+ * @param string $uri
+ * @param ConnectorInterface $connector
+ */
+ public function __construct($uri, ConnectorInterface $connector)
+ {
+ $this->uri = $uri;
+ $this->connector = $connector;
+ }
+
+ public function connect($_)
+ {
+ return $this->connector->connect($this->uri);
+ }
+}
diff --git a/vendor/react/socket/src/HappyEyeBallsConnectionBuilder.php b/vendor/react/socket/src/HappyEyeBallsConnectionBuilder.php
new file mode 100644
index 0000000..6bd0716
--- /dev/null
+++ b/vendor/react/socket/src/HappyEyeBallsConnectionBuilder.php
@@ -0,0 +1,333 @@
+<?php
+
+namespace React\Socket;
+
+use React\Dns\Model\Message;
+use React\Dns\Resolver\ResolverInterface;
+use React\EventLoop\LoopInterface;
+use React\EventLoop\TimerInterface;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+/**
+ * @internal
+ */
+final class HappyEyeBallsConnectionBuilder
+{
+ /**
+ * As long as we haven't connected yet keep popping an IP address of the connect queue until one of them
+ * succeeds or they all fail. We will wait 100ms between connection attempts as per RFC.
+ *
+ * @link https://tools.ietf.org/html/rfc8305#section-5
+ */
+ const CONNECTION_ATTEMPT_DELAY = 0.1;
+
+ /**
+ * Delay `A` lookup by 50ms sending out connection to IPv4 addresses when IPv6 records haven't
+ * resolved yet as per RFC.
+ *
+ * @link https://tools.ietf.org/html/rfc8305#section-3
+ */
+ const RESOLUTION_DELAY = 0.05;
+
+ public $loop;
+ public $connector;
+ public $resolver;
+ public $uri;
+ public $host;
+ public $resolved = array(
+ Message::TYPE_A => false,
+ Message::TYPE_AAAA => false,
+ );
+ public $resolverPromises = array();
+ public $connectionPromises = array();
+ public $connectQueue = array();
+ public $nextAttemptTimer;
+ public $parts;
+ public $ipsCount = 0;
+ public $failureCount = 0;
+ public $resolve;
+ public $reject;
+
+ public $lastErrorFamily;
+ public $lastError6;
+ public $lastError4;
+
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector, ResolverInterface $resolver, $uri, $host, $parts)
+ {
+ $this->loop = $loop;
+ $this->connector = $connector;
+ $this->resolver = $resolver;
+ $this->uri = $uri;
+ $this->host = $host;
+ $this->parts = $parts;
+ }
+
+ public function connect()
+ {
+ $timer = null;
+ $that = $this;
+ return new Promise\Promise(function ($resolve, $reject) use ($that, &$timer) {
+ $lookupResolve = function ($type) use ($that, $resolve, $reject) {
+ return function (array $ips) use ($that, $type, $resolve, $reject) {
+ unset($that->resolverPromises[$type]);
+ $that->resolved[$type] = true;
+
+ $that->mixIpsIntoConnectQueue($ips);
+
+ // start next connection attempt if not already awaiting next
+ if ($that->nextAttemptTimer === null && $that->connectQueue) {
+ $that->check($resolve, $reject);
+ }
+ };
+ };
+
+ $that->resolverPromises[Message::TYPE_AAAA] = $that->resolve(Message::TYPE_AAAA, $reject)->then($lookupResolve(Message::TYPE_AAAA));
+ $that->resolverPromises[Message::TYPE_A] = $that->resolve(Message::TYPE_A, $reject)->then(function (array $ips) use ($that, &$timer) {
+ // happy path: IPv6 has resolved already (or could not resolve), continue with IPv4 addresses
+ if ($that->resolved[Message::TYPE_AAAA] === true || !$ips) {
+ return $ips;
+ }
+
+ // Otherwise delay processing IPv4 lookup until short timer passes or IPv6 resolves in the meantime
+ $deferred = new Promise\Deferred();
+ $timer = $that->loop->addTimer($that::RESOLUTION_DELAY, function () use ($deferred, $ips) {
+ $deferred->resolve($ips);
+ });
+
+ $that->resolverPromises[Message::TYPE_AAAA]->then(function () use ($that, $timer, $deferred, $ips) {
+ $that->loop->cancelTimer($timer);
+ $deferred->resolve($ips);
+ });
+
+ return $deferred->promise();
+ })->then($lookupResolve(Message::TYPE_A));
+ }, function ($_, $reject) use ($that, &$timer) {
+ $reject(new \RuntimeException(
+ 'Connection to ' . $that->uri . ' cancelled' . (!$that->connectionPromises ? ' during DNS lookup' : '') . ' (ECONNABORTED)',
+ \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
+ ));
+ $_ = $reject = null;
+
+ $that->cleanUp();
+ if ($timer instanceof TimerInterface) {
+ $that->loop->cancelTimer($timer);
+ }
+ });
+ }
+
+ /**
+ * @internal
+ * @param int $type DNS query type
+ * @param callable $reject
+ * @return \React\Promise\PromiseInterface<string[]> Returns a promise that
+ * always resolves with a list of IP addresses on success or an empty
+ * list on error.
+ */
+ public function resolve($type, $reject)
+ {
+ $that = $this;
+ return $that->resolver->resolveAll($that->host, $type)->then(null, function (\Exception $e) use ($type, $reject, $that) {
+ unset($that->resolverPromises[$type]);
+ $that->resolved[$type] = true;
+
+ if ($type === Message::TYPE_A) {
+ $that->lastError4 = $e->getMessage();
+ $that->lastErrorFamily = 4;
+ } else {
+ $that->lastError6 = $e->getMessage();
+ $that->lastErrorFamily = 6;
+ }
+
+ // cancel next attempt timer when there are no more IPs to connect to anymore
+ if ($that->nextAttemptTimer !== null && !$that->connectQueue) {
+ $that->loop->cancelTimer($that->nextAttemptTimer);
+ $that->nextAttemptTimer = null;
+ }
+
+ if ($that->hasBeenResolved() && $that->ipsCount === 0) {
+ $reject(new \RuntimeException(
+ $that->error(),
+ 0,
+ $e
+ ));
+ }
+
+ // Exception already handled above, so don't throw an unhandled rejection here
+ return array();
+ });
+ }
+
+ /**
+ * @internal
+ */
+ public function check($resolve, $reject)
+ {
+ $ip = \array_shift($this->connectQueue);
+
+ // start connection attempt and remember array position to later unset again
+ $this->connectionPromises[] = $this->attemptConnection($ip);
+ \end($this->connectionPromises);
+ $index = \key($this->connectionPromises);
+
+ $that = $this;
+ $that->connectionPromises[$index]->then(function ($connection) use ($that, $index, $resolve) {
+ unset($that->connectionPromises[$index]);
+
+ $that->cleanUp();
+
+ $resolve($connection);
+ }, function (\Exception $e) use ($that, $index, $ip, $resolve, $reject) {
+ unset($that->connectionPromises[$index]);
+
+ $that->failureCount++;
+
+ $message = \preg_replace('/^(Connection to [^ ]+)[&?]hostname=[^ &]+/', '$1', $e->getMessage());
+ if (\strpos($ip, ':') === false) {
+ $that->lastError4 = $message;
+ $that->lastErrorFamily = 4;
+ } else {
+ $that->lastError6 = $message;
+ $that->lastErrorFamily = 6;
+ }
+
+ // start next connection attempt immediately on error
+ if ($that->connectQueue) {
+ if ($that->nextAttemptTimer !== null) {
+ $that->loop->cancelTimer($that->nextAttemptTimer);
+ $that->nextAttemptTimer = null;
+ }
+
+ $that->check($resolve, $reject);
+ }
+
+ if ($that->hasBeenResolved() === false) {
+ return;
+ }
+
+ if ($that->ipsCount === $that->failureCount) {
+ $that->cleanUp();
+
+ $reject(new \RuntimeException(
+ $that->error(),
+ $e->getCode(),
+ $e
+ ));
+ }
+ });
+
+ // Allow next connection attempt in 100ms: https://tools.ietf.org/html/rfc8305#section-5
+ // Only start timer when more IPs are queued or when DNS query is still pending (might add more IPs)
+ if ($this->nextAttemptTimer === null && (\count($this->connectQueue) > 0 || $this->resolved[Message::TYPE_A] === false || $this->resolved[Message::TYPE_AAAA] === false)) {
+ $this->nextAttemptTimer = $this->loop->addTimer(self::CONNECTION_ATTEMPT_DELAY, function () use ($that, $resolve, $reject) {
+ $that->nextAttemptTimer = null;
+
+ if ($that->connectQueue) {
+ $that->check($resolve, $reject);
+ }
+ });
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function attemptConnection($ip)
+ {
+ $uri = Connector::uri($this->parts, $this->host, $ip);
+
+ return $this->connector->connect($uri);
+ }
+
+ /**
+ * @internal
+ */
+ public function cleanUp()
+ {
+ // clear list of outstanding IPs to avoid creating new connections
+ $this->connectQueue = array();
+
+ foreach ($this->connectionPromises as $connectionPromise) {
+ if ($connectionPromise instanceof CancellablePromiseInterface) {
+ $connectionPromise->cancel();
+ }
+ }
+
+ foreach ($this->resolverPromises as $resolverPromise) {
+ if ($resolverPromise instanceof CancellablePromiseInterface) {
+ $resolverPromise->cancel();
+ }
+ }
+
+ if ($this->nextAttemptTimer instanceof TimerInterface) {
+ $this->loop->cancelTimer($this->nextAttemptTimer);
+ $this->nextAttemptTimer = null;
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function hasBeenResolved()
+ {
+ foreach ($this->resolved as $typeHasBeenResolved) {
+ if ($typeHasBeenResolved === false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Mixes an array of IP addresses into the connect queue in such a way they alternate when attempting to connect.
+ * The goal behind it is first attempt to connect to IPv6, then to IPv4, then to IPv6 again until one of those
+ * attempts succeeds.
+ *
+ * @link https://tools.ietf.org/html/rfc8305#section-4
+ *
+ * @internal
+ */
+ public function mixIpsIntoConnectQueue(array $ips)
+ {
+ \shuffle($ips);
+ $this->ipsCount += \count($ips);
+ $connectQueueStash = $this->connectQueue;
+ $this->connectQueue = array();
+ while (\count($connectQueueStash) > 0 || \count($ips) > 0) {
+ if (\count($ips) > 0) {
+ $this->connectQueue[] = \array_shift($ips);
+ }
+ if (\count($connectQueueStash) > 0) {
+ $this->connectQueue[] = \array_shift($connectQueueStash);
+ }
+ }
+ }
+
+ /**
+ * @internal
+ * @return string
+ */
+ public function error()
+ {
+ if ($this->lastError4 === $this->lastError6) {
+ $message = $this->lastError6;
+ } elseif ($this->lastErrorFamily === 6) {
+ $message = 'Last error for IPv6: ' . $this->lastError6 . '. Previous error for IPv4: ' . $this->lastError4;
+ } else {
+ $message = 'Last error for IPv4: ' . $this->lastError4 . '. Previous error for IPv6: ' . $this->lastError6;
+ }
+
+ if ($this->hasBeenResolved() && $this->ipsCount === 0) {
+ if ($this->lastError6 === $this->lastError4) {
+ $message = ' during DNS lookup: ' . $this->lastError6;
+ } else {
+ $message = ' during DNS lookup. ' . $message;
+ }
+ } else {
+ $message = ': ' . $message;
+ }
+
+ return 'Connection to ' . $this->uri . ' failed' . $message;
+ }
+}
diff --git a/vendor/react/socket/src/HappyEyeBallsConnector.php b/vendor/react/socket/src/HappyEyeBallsConnector.php
new file mode 100644
index 0000000..4b04f77
--- /dev/null
+++ b/vendor/react/socket/src/HappyEyeBallsConnector.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace React\Socket;
+
+use React\Dns\Resolver\ResolverInterface;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+
+final class HappyEyeBallsConnector implements ConnectorInterface
+{
+ private $loop;
+ private $connector;
+ private $resolver;
+
+ public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null, ResolverInterface $resolver = null)
+ {
+ // $connector and $resolver arguments are actually required, marked
+ // optional for technical reasons only. Nullable $loop without default
+ // requires PHP 7.1, null default is also supported in legacy PHP
+ // versions, but required parameters are not allowed after arguments
+ // with null default. Mark all parameters optional and check accordingly.
+ if ($connector === null || $resolver === null) {
+ throw new \InvalidArgumentException('Missing required $connector or $resolver argument');
+ }
+
+ $this->loop = $loop ?: Loop::get();
+ $this->connector = $connector;
+ $this->resolver = $resolver;
+ }
+
+ public function connect($uri)
+ {
+ $original = $uri;
+ if (\strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ $parts = \parse_url($uri);
+ if (isset($parts['scheme'])) {
+ unset($parts['scheme']);
+ }
+ } else {
+ $parts = \parse_url($uri);
+ }
+
+ if (!$parts || !isset($parts['host'])) {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $original . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ $host = \trim($parts['host'], '[]');
+
+ // skip DNS lookup / URI manipulation if this URI already contains an IP
+ if (@\inet_pton($host) !== false) {
+ return $this->connector->connect($original);
+ }
+
+ $builder = new HappyEyeBallsConnectionBuilder(
+ $this->loop,
+ $this->connector,
+ $this->resolver,
+ $uri,
+ $host,
+ $parts
+ );
+ return $builder->connect();
+ }
+}
diff --git a/vendor/react/socket/src/LimitingServer.php b/vendor/react/socket/src/LimitingServer.php
new file mode 100644
index 0000000..d19000b
--- /dev/null
+++ b/vendor/react/socket/src/LimitingServer.php
@@ -0,0 +1,203 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use Exception;
+use OverflowException;
+
+/**
+ * The `LimitingServer` decorator wraps a given `ServerInterface` and is responsible
+ * for limiting and keeping track of open connections to this server instance.
+ *
+ * Whenever the underlying server emits a `connection` event, it will check its
+ * limits and then either
+ * - keep track of this connection by adding it to the list of
+ * open connections and then forward the `connection` event
+ * - or reject (close) the connection when its limits are exceeded and will
+ * forward an `error` event instead.
+ *
+ * Whenever a connection closes, it will remove this connection from the list of
+ * open connections.
+ *
+ * ```php
+ * $server = new React\Socket\LimitingServer($server, 100);
+ * $server->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * See also the `ServerInterface` for more details.
+ *
+ * @see ServerInterface
+ * @see ConnectionInterface
+ */
+class LimitingServer extends EventEmitter implements ServerInterface
+{
+ private $connections = array();
+ private $server;
+ private $limit;
+
+ private $pauseOnLimit = false;
+ private $autoPaused = false;
+ private $manuPaused = false;
+
+ /**
+ * Instantiates a new LimitingServer.
+ *
+ * You have to pass a maximum number of open connections to ensure
+ * the server will automatically reject (close) connections once this limit
+ * is exceeded. In this case, it will emit an `error` event to inform about
+ * this and no `connection` event will be emitted.
+ *
+ * ```php
+ * $server = new React\Socket\LimitingServer($server, 100);
+ * $server->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * You MAY pass a `null` limit in order to put no limit on the number of
+ * open connections and keep accepting new connection until you run out of
+ * operating system resources (such as open file handles). This may be
+ * useful if you do not want to take care of applying a limit but still want
+ * to use the `getConnections()` method.
+ *
+ * You can optionally configure the server to pause accepting new
+ * connections once the connection limit is reached. In this case, it will
+ * pause the underlying server and no longer process any new connections at
+ * all, thus also no longer closing any excessive connections.
+ * The underlying operating system is responsible for keeping a backlog of
+ * pending connections until its limit is reached, at which point it will
+ * start rejecting further connections.
+ * Once the server is below the connection limit, it will continue consuming
+ * connections from the backlog and will process any outstanding data on
+ * each connection.
+ * This mode may be useful for some protocols that are designed to wait for
+ * a response message (such as HTTP), but may be less useful for other
+ * protocols that demand immediate responses (such as a "welcome" message in
+ * an interactive chat).
+ *
+ * ```php
+ * $server = new React\Socket\LimitingServer($server, 100, true);
+ * $server->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * @param ServerInterface $server
+ * @param int|null $connectionLimit
+ * @param bool $pauseOnLimit
+ */
+ public function __construct(ServerInterface $server, $connectionLimit, $pauseOnLimit = false)
+ {
+ $this->server = $server;
+ $this->limit = $connectionLimit;
+ if ($connectionLimit !== null) {
+ $this->pauseOnLimit = $pauseOnLimit;
+ }
+
+ $this->server->on('connection', array($this, 'handleConnection'));
+ $this->server->on('error', array($this, 'handleError'));
+ }
+
+ /**
+ * Returns an array with all currently active connections
+ *
+ * ```php
+ * foreach ($server->getConnection() as $connection) {
+ * $connection->write('Hi!');
+ * }
+ * ```
+ *
+ * @return ConnectionInterface[]
+ */
+ public function getConnections()
+ {
+ return $this->connections;
+ }
+
+ public function getAddress()
+ {
+ return $this->server->getAddress();
+ }
+
+ public function pause()
+ {
+ if (!$this->manuPaused) {
+ $this->manuPaused = true;
+
+ if (!$this->autoPaused) {
+ $this->server->pause();
+ }
+ }
+ }
+
+ public function resume()
+ {
+ if ($this->manuPaused) {
+ $this->manuPaused = false;
+
+ if (!$this->autoPaused) {
+ $this->server->resume();
+ }
+ }
+ }
+
+ public function close()
+ {
+ $this->server->close();
+ }
+
+ /** @internal */
+ public function handleConnection(ConnectionInterface $connection)
+ {
+ // close connection if limit exceeded
+ if ($this->limit !== null && \count($this->connections) >= $this->limit) {
+ $this->handleError(new \OverflowException('Connection closed because server reached connection limit'));
+ $connection->close();
+ return;
+ }
+
+ $this->connections[] = $connection;
+ $that = $this;
+ $connection->on('close', function () use ($that, $connection) {
+ $that->handleDisconnection($connection);
+ });
+
+ // pause accepting new connections if limit exceeded
+ if ($this->pauseOnLimit && !$this->autoPaused && \count($this->connections) >= $this->limit) {
+ $this->autoPaused = true;
+
+ if (!$this->manuPaused) {
+ $this->server->pause();
+ }
+ }
+
+ $this->emit('connection', array($connection));
+ }
+
+ /** @internal */
+ public function handleDisconnection(ConnectionInterface $connection)
+ {
+ unset($this->connections[\array_search($connection, $this->connections)]);
+
+ // continue accepting new connection if below limit
+ if ($this->autoPaused && \count($this->connections) < $this->limit) {
+ $this->autoPaused = false;
+
+ if (!$this->manuPaused) {
+ $this->server->resume();
+ }
+ }
+ }
+
+ /** @internal */
+ public function handleError(\Exception $error)
+ {
+ $this->emit('error', array($error));
+ }
+}
diff --git a/vendor/react/socket/src/SecureConnector.php b/vendor/react/socket/src/SecureConnector.php
new file mode 100644
index 0000000..03c6e36
--- /dev/null
+++ b/vendor/react/socket/src/SecureConnector.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace React\Socket;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+use BadMethodCallException;
+use InvalidArgumentException;
+use UnexpectedValueException;
+
+final class SecureConnector implements ConnectorInterface
+{
+ private $connector;
+ private $streamEncryption;
+ private $context;
+
+ public function __construct(ConnectorInterface $connector, LoopInterface $loop = null, array $context = array())
+ {
+ $this->connector = $connector;
+ $this->streamEncryption = new StreamEncryption($loop ?: Loop::get(), false);
+ $this->context = $context;
+ }
+
+ public function connect($uri)
+ {
+ if (!\function_exists('stream_socket_enable_crypto')) {
+ return Promise\reject(new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)')); // @codeCoverageIgnore
+ }
+
+ if (\strpos($uri, '://') === false) {
+ $uri = 'tls://' . $uri;
+ }
+
+ $parts = \parse_url($uri);
+ if (!$parts || !isset($parts['scheme']) || $parts['scheme'] !== 'tls') {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $uri . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ $context = $this->context;
+ $encryption = $this->streamEncryption;
+ $connected = false;
+ $promise = $this->connector->connect(
+ \str_replace('tls://', '', $uri)
+ )->then(function (ConnectionInterface $connection) use ($context, $encryption, $uri, &$promise, &$connected) {
+ // (unencrypted) TCP/IP connection succeeded
+ $connected = true;
+
+ if (!$connection instanceof Connection) {
+ $connection->close();
+ throw new \UnexpectedValueException('Base connector does not use internal Connection class exposing stream resource');
+ }
+
+ // set required SSL/TLS context options
+ foreach ($context as $name => $value) {
+ \stream_context_set_option($connection->stream, 'ssl', $name, $value);
+ }
+
+ // try to enable encryption
+ return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
+ // establishing encryption failed => close invalid connection and return error
+ $connection->close();
+
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' failed during TLS handshake: ' . $error->getMessage(),
+ $error->getCode()
+ );
+ });
+ }, function (\Exception $e) use ($uri) {
+ if ($e instanceof \RuntimeException) {
+ $message = \preg_replace('/^Connection to [^ ]+/', '', $e->getMessage());
+ $e = new \RuntimeException(
+ 'Connection to ' . $uri . $message,
+ $e->getCode(),
+ $e
+ );
+
+ // avoid garbage references by replacing all closures in call stack.
+ // what a lovely piece of code!
+ $r = new \ReflectionProperty('Exception', 'trace');
+ $r->setAccessible(true);
+ $trace = $r->getValue($e);
+
+ // Exception trace arguments are not available on some PHP 7.4 installs
+ // @codeCoverageIgnoreStart
+ foreach ($trace as &$one) {
+ if (isset($one['args'])) {
+ foreach ($one['args'] as &$arg) {
+ if ($arg instanceof \Closure) {
+ $arg = 'Object(' . \get_class($arg) . ')';
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ $r->setValue($e, $trace);
+ }
+
+ throw $e;
+ });
+
+ return new \React\Promise\Promise(
+ function ($resolve, $reject) use ($promise) {
+ $promise->then($resolve, $reject);
+ },
+ function ($_, $reject) use (&$promise, $uri, &$connected) {
+ if ($connected) {
+ $reject(new \RuntimeException(
+ 'Connection to ' . $uri . ' cancelled during TLS handshake (ECONNABORTED)',
+ \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
+ ));
+ }
+
+ $promise->cancel();
+ $promise = null;
+ }
+ );
+ }
+}
diff --git a/vendor/react/socket/src/SecureServer.php b/vendor/react/socket/src/SecureServer.php
new file mode 100644
index 0000000..d0525c9
--- /dev/null
+++ b/vendor/react/socket/src/SecureServer.php
@@ -0,0 +1,206 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use BadMethodCallException;
+use UnexpectedValueException;
+
+/**
+ * The `SecureServer` class implements the `ServerInterface` and is responsible
+ * for providing a secure TLS (formerly known as SSL) server.
+ *
+ * It does so by wrapping a `TcpServer` instance which waits for plaintext
+ * TCP/IP connections and then performs a TLS handshake for each connection.
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(8000);
+ * $server = new React\Socket\SecureServer($server, null, array(
+ * // tls context options here…
+ * ));
+ * ```
+ *
+ * Whenever a client completes the TLS handshake, it will emit a `connection` event
+ * with a connection instance implementing [`ConnectionInterface`](#connectioninterface):
+ *
+ * ```php
+ * $server->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * echo 'Secure connection from' . $connection->getRemoteAddress() . PHP_EOL;
+ *
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * Whenever a client fails to perform a successful TLS handshake, it will emit an
+ * `error` event and then close the underlying TCP/IP connection:
+ *
+ * ```php
+ * $server->on('error', function (Exception $e) {
+ * echo 'Error' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also the `ServerInterface` for more details.
+ *
+ * Note that the `SecureServer` class is a concrete implementation for TLS sockets.
+ * If you want to typehint in your higher-level protocol implementation, you SHOULD
+ * use the generic `ServerInterface` instead.
+ *
+ * @see ServerInterface
+ * @see ConnectionInterface
+ */
+final class SecureServer extends EventEmitter implements ServerInterface
+{
+ private $tcp;
+ private $encryption;
+ private $context;
+
+ /**
+ * Creates a secure TLS server and starts waiting for incoming connections
+ *
+ * It does so by wrapping a `TcpServer` instance which waits for plaintext
+ * TCP/IP connections and then performs a TLS handshake for each connection.
+ * It thus requires valid [TLS context options],
+ * which in its most basic form may look something like this if you're using a
+ * PEM encoded certificate file:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(8000);
+ * $server = new React\Socket\SecureServer($server, null, array(
+ * 'local_cert' => 'server.pem'
+ * ));
+ * ```
+ *
+ * Note that the certificate file will not be loaded on instantiation but when an
+ * incoming connection initializes its TLS context.
+ * This implies that any invalid certificate file paths or contents will only cause
+ * an `error` event at a later time.
+ *
+ * If your private key is encrypted with a passphrase, you have to specify it
+ * like this:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(8000);
+ * $server = new React\Socket\SecureServer($server, null, array(
+ * 'local_cert' => 'server.pem',
+ * 'passphrase' => 'secret'
+ * ));
+ * ```
+ *
+ * Note that available [TLS context options],
+ * their defaults and effects of changing these may vary depending on your system
+ * and/or PHP version.
+ * Passing unknown context options has no effect.
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * Advanced usage: Despite allowing any `ServerInterface` as first parameter,
+ * you SHOULD pass a `TcpServer` instance as first parameter, unless you
+ * know what you're doing.
+ * Internally, the `SecureServer` has to set the required TLS context options on
+ * the underlying stream resources.
+ * These resources are not exposed through any of the interfaces defined in this
+ * package, but only through the internal `Connection` class.
+ * The `TcpServer` class is guaranteed to emit connections that implement
+ * the `ConnectionInterface` and uses the internal `Connection` class in order to
+ * expose these underlying resources.
+ * If you use a custom `ServerInterface` and its `connection` event does not
+ * meet this requirement, the `SecureServer` will emit an `error` event and
+ * then close the underlying connection.
+ *
+ * @param ServerInterface|TcpServer $tcp
+ * @param ?LoopInterface $loop
+ * @param array $context
+ * @throws BadMethodCallException for legacy HHVM < 3.8 due to lack of support
+ * @see TcpServer
+ * @link https://www.php.net/manual/en/context.ssl.php for TLS context options
+ */
+ public function __construct(ServerInterface $tcp, LoopInterface $loop = null, array $context = array())
+ {
+ if (!\function_exists('stream_socket_enable_crypto')) {
+ throw new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)'); // @codeCoverageIgnore
+ }
+
+ // default to empty passphrase to suppress blocking passphrase prompt
+ $context += array(
+ 'passphrase' => ''
+ );
+
+ $this->tcp = $tcp;
+ $this->encryption = new StreamEncryption($loop ?: Loop::get());
+ $this->context = $context;
+
+ $that = $this;
+ $this->tcp->on('connection', function ($connection) use ($that) {
+ $that->handleConnection($connection);
+ });
+ $this->tcp->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error));
+ });
+ }
+
+ public function getAddress()
+ {
+ $address = $this->tcp->getAddress();
+ if ($address === null) {
+ return null;
+ }
+
+ return \str_replace('tcp://' , 'tls://', $address);
+ }
+
+ public function pause()
+ {
+ $this->tcp->pause();
+ }
+
+ public function resume()
+ {
+ $this->tcp->resume();
+ }
+
+ public function close()
+ {
+ return $this->tcp->close();
+ }
+
+ /** @internal */
+ public function handleConnection(ConnectionInterface $connection)
+ {
+ if (!$connection instanceof Connection) {
+ $this->emit('error', array(new \UnexpectedValueException('Base server does not use internal Connection class exposing stream resource')));
+ $connection->close();
+ return;
+ }
+
+ foreach ($this->context as $name => $value) {
+ \stream_context_set_option($connection->stream, 'ssl', $name, $value);
+ }
+
+ // get remote address before starting TLS handshake in case connection closes during handshake
+ $remote = $connection->getRemoteAddress();
+ $that = $this;
+
+ $this->encryption->enable($connection)->then(
+ function ($conn) use ($that) {
+ $that->emit('connection', array($conn));
+ },
+ function ($error) use ($that, $connection, $remote) {
+ $error = new \RuntimeException(
+ 'Connection from ' . $remote . ' failed during TLS handshake: ' . $error->getMessage(),
+ $error->getCode()
+ );
+
+ $that->emit('error', array($error));
+ $connection->close();
+ }
+ );
+ }
+}
diff --git a/vendor/react/socket/src/Server.php b/vendor/react/socket/src/Server.php
new file mode 100644
index 0000000..7d4111e
--- /dev/null
+++ b/vendor/react/socket/src/Server.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use Exception;
+
+/**
+ * @deprecated 1.9.0 See `SocketServer` instead
+ * @see SocketServer
+ */
+final class Server extends EventEmitter implements ServerInterface
+{
+ private $server;
+
+ /**
+ * [Deprecated] `Server`
+ *
+ * This class exists for BC reasons only and should not be used anymore.
+ *
+ * ```php
+ * // deprecated
+ * $socket = new React\Socket\Server(0);
+ * $socket = new React\Socket\Server('127.0.0.1:8000');
+ * $socket = new React\Socket\Server('127.0.0.1:8000', null, $context);
+ * $socket = new React\Socket\Server('127.0.0.1:8000', $loop, $context);
+ *
+ * // new
+ * $socket = new React\Socket\SocketServer('127.0.0.1:0');
+ * $socket = new React\Socket\SocketServer('127.0.0.1:8000');
+ * $socket = new React\Socket\SocketServer('127.0.0.1:8000', $context);
+ * $socket = new React\Socket\SocketServer('127.0.0.1:8000', $context, $loop);
+ * ```
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * For BC reasons, you can also pass the TCP socket context options as a simple
+ * array without wrapping this in another array under the `tcp` key.
+ *
+ * @param string|int $uri
+ * @param LoopInterface $loop
+ * @param array $context
+ * @deprecated 1.9.0 See `SocketServer` instead
+ * @see SocketServer
+ */
+ public function __construct($uri, LoopInterface $loop = null, array $context = array())
+ {
+ $loop = $loop ?: Loop::get();
+
+ // sanitize TCP context options if not properly wrapped
+ if ($context && (!isset($context['tcp']) && !isset($context['tls']) && !isset($context['unix']))) {
+ $context = array('tcp' => $context);
+ }
+
+ // apply default options if not explicitly given
+ $context += array(
+ 'tcp' => array(),
+ 'tls' => array(),
+ 'unix' => array()
+ );
+
+ $scheme = 'tcp';
+ $pos = \strpos($uri, '://');
+ if ($pos !== false) {
+ $scheme = \substr($uri, 0, $pos);
+ }
+
+ if ($scheme === 'unix') {
+ $server = new UnixServer($uri, $loop, $context['unix']);
+ } else {
+ $server = new TcpServer(str_replace('tls://', '', $uri), $loop, $context['tcp']);
+
+ if ($scheme === 'tls') {
+ $server = new SecureServer($server, $loop, $context['tls']);
+ }
+ }
+
+ $this->server = $server;
+
+ $that = $this;
+ $server->on('connection', function (ConnectionInterface $conn) use ($that) {
+ $that->emit('connection', array($conn));
+ });
+ $server->on('error', function (Exception $error) use ($that) {
+ $that->emit('error', array($error));
+ });
+ }
+
+ public function getAddress()
+ {
+ return $this->server->getAddress();
+ }
+
+ public function pause()
+ {
+ $this->server->pause();
+ }
+
+ public function resume()
+ {
+ $this->server->resume();
+ }
+
+ public function close()
+ {
+ $this->server->close();
+ }
+}
diff --git a/vendor/react/socket/src/ServerInterface.php b/vendor/react/socket/src/ServerInterface.php
new file mode 100644
index 0000000..aa79fa1
--- /dev/null
+++ b/vendor/react/socket/src/ServerInterface.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitterInterface;
+
+/**
+ * The `ServerInterface` is responsible for providing an interface for accepting
+ * incoming streaming connections, such as a normal TCP/IP connection.
+ *
+ * Most higher-level components (such as a HTTP server) accept an instance
+ * implementing this interface to accept incoming streaming connections.
+ * This is usually done via dependency injection, so it's fairly simple to actually
+ * swap this implementation against any other implementation of this interface.
+ * This means that you SHOULD typehint against this interface instead of a concrete
+ * implementation of this interface.
+ *
+ * Besides defining a few methods, this interface also implements the
+ * `EventEmitterInterface` which allows you to react to certain events:
+ *
+ * connection event:
+ * The `connection` event will be emitted whenever a new connection has been
+ * established, i.e. a new client connects to this server socket:
+ *
+ * ```php
+ * $socket->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * echo 'new connection' . PHP_EOL;
+ * });
+ * ```
+ *
+ * See also the `ConnectionInterface` for more details about handling the
+ * incoming connection.
+ *
+ * error event:
+ * The `error` event will be emitted whenever there's an error accepting a new
+ * connection from a client.
+ *
+ * ```php
+ * $socket->on('error', function (Exception $e) {
+ * echo 'error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * Note that this is not a fatal error event, i.e. the server keeps listening for
+ * new connections even after this event.
+ *
+ * @see ConnectionInterface
+ */
+interface ServerInterface extends EventEmitterInterface
+{
+ /**
+ * Returns the full address (URI) this server is currently listening on
+ *
+ * ```php
+ * $address = $socket->getAddress();
+ * echo 'Server listening on ' . $address . PHP_EOL;
+ * ```
+ *
+ * If the address can not be determined or is unknown at this time (such as
+ * after the socket has been closed), it MAY return a `NULL` value instead.
+ *
+ * Otherwise, it will return the full address (URI) as a string value, such
+ * as `tcp://127.0.0.1:8080`, `tcp://[::1]:80` or `tls://127.0.0.1:443`.
+ * Note that individual URI components are application specific and depend
+ * on the underlying transport protocol.
+ *
+ * If this is a TCP/IP based server and you only want the local port, you may
+ * use something like this:
+ *
+ * ```php
+ * $address = $socket->getAddress();
+ * $port = parse_url($address, PHP_URL_PORT);
+ * echo 'Server listening on port ' . $port . PHP_EOL;
+ * ```
+ *
+ * @return ?string the full listening address (URI) or NULL if it is unknown (not applicable to this server socket or already closed)
+ */
+ public function getAddress();
+
+ /**
+ * Pauses accepting new incoming connections.
+ *
+ * Removes the socket resource from the EventLoop and thus stop accepting
+ * new connections. Note that the listening socket stays active and is not
+ * closed.
+ *
+ * This means that new incoming connections will stay pending in the
+ * operating system backlog until its configurable backlog is filled.
+ * Once the backlog is filled, the operating system may reject further
+ * incoming connections until the backlog is drained again by resuming
+ * to accept new connections.
+ *
+ * Once the server is paused, no futher `connection` events SHOULD
+ * be emitted.
+ *
+ * ```php
+ * $socket->pause();
+ *
+ * $socket->on('connection', assertShouldNeverCalled());
+ * ```
+ *
+ * This method is advisory-only, though generally not recommended, the
+ * server MAY continue emitting `connection` events.
+ *
+ * Unless otherwise noted, a successfully opened server SHOULD NOT start
+ * in paused state.
+ *
+ * You can continue processing events by calling `resume()` again.
+ *
+ * Note that both methods can be called any number of times, in particular
+ * calling `pause()` more than once SHOULD NOT have any effect.
+ * Similarly, calling this after `close()` is a NO-OP.
+ *
+ * @see self::resume()
+ * @return void
+ */
+ public function pause();
+
+ /**
+ * Resumes accepting new incoming connections.
+ *
+ * Re-attach the socket resource to the EventLoop after a previous `pause()`.
+ *
+ * ```php
+ * $socket->pause();
+ *
+ * Loop::addTimer(1.0, function () use ($socket) {
+ * $socket->resume();
+ * });
+ * ```
+ *
+ * Note that both methods can be called any number of times, in particular
+ * calling `resume()` without a prior `pause()` SHOULD NOT have any effect.
+ * Similarly, calling this after `close()` is a NO-OP.
+ *
+ * @see self::pause()
+ * @return void
+ */
+ public function resume();
+
+ /**
+ * Shuts down this listening socket
+ *
+ * This will stop listening for new incoming connections on this socket.
+ *
+ * Calling this method more than once on the same instance is a NO-OP.
+ *
+ * @return void
+ */
+ public function close();
+}
diff --git a/vendor/react/socket/src/SocketServer.php b/vendor/react/socket/src/SocketServer.php
new file mode 100644
index 0000000..2ea03ba
--- /dev/null
+++ b/vendor/react/socket/src/SocketServer.php
@@ -0,0 +1,187 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\LoopInterface;
+
+final class SocketServer extends EventEmitter implements ServerInterface
+{
+ private $server;
+
+ /**
+ * The `SocketServer` class is the main class in this package that implements the `ServerInterface` and
+ * allows you to accept incoming streaming connections, such as plaintext TCP/IP or secure TLS connection streams.
+ *
+ * ```php
+ * $socket = new React\Socket\SocketServer('127.0.0.1:0');
+ * $socket = new React\Socket\SocketServer('127.0.0.1:8000');
+ * $socket = new React\Socket\SocketServer('127.0.0.1:8000', $context);
+ * ```
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param string $uri
+ * @param array $context
+ * @param ?LoopInterface $loop
+ * @throws \InvalidArgumentException if the listening address is invalid
+ * @throws \RuntimeException if listening on this address fails (already in use etc.)
+ */
+ public function __construct($uri, array $context = array(), LoopInterface $loop = null)
+ {
+ // apply default options if not explicitly given
+ $context += array(
+ 'tcp' => array(),
+ 'tls' => array(),
+ 'unix' => array()
+ );
+
+ $scheme = 'tcp';
+ $pos = \strpos($uri, '://');
+ if ($pos !== false) {
+ $scheme = \substr($uri, 0, $pos);
+ }
+
+ if ($scheme === 'unix') {
+ $server = new UnixServer($uri, $loop, $context['unix']);
+ } elseif ($scheme === 'php') {
+ $server = new FdServer($uri, $loop);
+ } else {
+ if (preg_match('#^(?:\w+://)?\d+$#', $uri)) {
+ throw new \InvalidArgumentException(
+ 'Invalid URI given (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ );
+ }
+
+ $server = new TcpServer(str_replace('tls://', '', $uri), $loop, $context['tcp']);
+
+ if ($scheme === 'tls') {
+ $server = new SecureServer($server, $loop, $context['tls']);
+ }
+ }
+
+ $this->server = $server;
+
+ $that = $this;
+ $server->on('connection', function (ConnectionInterface $conn) use ($that) {
+ $that->emit('connection', array($conn));
+ });
+ $server->on('error', function (\Exception $error) use ($that) {
+ $that->emit('error', array($error));
+ });
+ }
+
+ public function getAddress()
+ {
+ return $this->server->getAddress();
+ }
+
+ public function pause()
+ {
+ $this->server->pause();
+ }
+
+ public function resume()
+ {
+ $this->server->resume();
+ }
+
+ public function close()
+ {
+ $this->server->close();
+ }
+
+ /**
+ * [internal] Internal helper method to accept new connection from given server socket
+ *
+ * @param resource $socket server socket to accept connection from
+ * @return resource new client socket if any
+ * @throws \RuntimeException if accepting fails
+ * @internal
+ */
+ public static function accept($socket)
+ {
+ $newSocket = @\stream_socket_accept($socket, 0);
+
+ if (false === $newSocket) {
+ // Match errstr from PHP's warning message.
+ // stream_socket_accept(): accept failed: Connection timed out
+ $error = \error_get_last();
+ $errstr = \preg_replace('#.*: #', '', $error['message']);
+ $errno = self::errno($errstr);
+
+ throw new \RuntimeException(
+ 'Unable to accept new connection: ' . $errstr . self::errconst($errno),
+ $errno
+ );
+ }
+
+ return $newSocket;
+ }
+
+ /**
+ * [Internal] Returns errno value for given errstr
+ *
+ * The errno and errstr values describes the type of error that has been
+ * encountered. This method tries to look up the given errstr and find a
+ * matching errno value which can be useful to provide more context to error
+ * messages. It goes through the list of known errno constants when
+ * ext-sockets is available to find an errno matching the given errstr.
+ *
+ * @param string $errstr
+ * @return int errno value (e.g. value of `SOCKET_ECONNREFUSED`) or 0 if not found
+ * @internal
+ * @copyright Copyright (c) 2018 Christian Lück, taken from https://github.com/clue/errno with permission
+ * @codeCoverageIgnore
+ */
+ public static function errno($errstr)
+ {
+ if (\function_exists('socket_strerror')) {
+ foreach (\get_defined_constants(false) as $name => $value) {
+ if (\strpos($name, 'SOCKET_E') === 0 && \socket_strerror($value) === $errstr) {
+ return $value;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * [Internal] Returns errno constant name for given errno value
+ *
+ * The errno value describes the type of error that has been encountered.
+ * This method tries to look up the given errno value and find a matching
+ * errno constant name which can be useful to provide more context and more
+ * descriptive error messages. It goes through the list of known errno
+ * constants when ext-sockets is available to find the matching errno
+ * constant name.
+ *
+ * Because this method is used to append more context to error messages, the
+ * constant name will be prefixed with a space and put between parenthesis
+ * when found.
+ *
+ * @param int $errno
+ * @return string e.g. ` (ECONNREFUSED)` or empty string if no matching const for the given errno could be found
+ * @internal
+ * @copyright Copyright (c) 2018 Christian Lück, taken from https://github.com/clue/errno with permission
+ * @codeCoverageIgnore
+ */
+ public static function errconst($errno)
+ {
+ if (\function_exists('socket_strerror')) {
+ foreach (\get_defined_constants(false) as $name => $value) {
+ if ($value === $errno && \strpos($name, 'SOCKET_E') === 0) {
+ return ' (' . \substr($name, 7) . ')';
+ }
+ }
+ }
+
+ return '';
+ }
+}
diff --git a/vendor/react/socket/src/StreamEncryption.php b/vendor/react/socket/src/StreamEncryption.php
new file mode 100644
index 0000000..4aa7fca
--- /dev/null
+++ b/vendor/react/socket/src/StreamEncryption.php
@@ -0,0 +1,141 @@
+<?php
+
+namespace React\Socket;
+
+use React\EventLoop\LoopInterface;
+use React\Promise\Deferred;
+use RuntimeException;
+use UnexpectedValueException;
+
+/**
+ * This class is considered internal and its API should not be relied upon
+ * outside of Socket.
+ *
+ * @internal
+ */
+class StreamEncryption
+{
+ private $loop;
+ private $method;
+ private $server;
+
+ public function __construct(LoopInterface $loop, $server = true)
+ {
+ $this->loop = $loop;
+ $this->server = $server;
+
+ // support TLSv1.0+ by default and exclude legacy SSLv2/SSLv3.
+ // As of PHP 7.2+ the main crypto method constant includes all TLS versions.
+ // As of PHP 5.6+ the crypto method is a bitmask, so we explicitly include all TLS versions.
+ // For legacy PHP < 5.6 the crypto method is a single value only and this constant includes all TLS versions.
+ // @link https://3v4l.org/9PSST
+ if ($server) {
+ $this->method = \STREAM_CRYPTO_METHOD_TLS_SERVER;
+
+ if (\PHP_VERSION_ID < 70200 && \PHP_VERSION_ID >= 50600) {
+ $this->method |= \STREAM_CRYPTO_METHOD_TLSv1_0_SERVER | \STREAM_CRYPTO_METHOD_TLSv1_1_SERVER | \STREAM_CRYPTO_METHOD_TLSv1_2_SERVER; // @codeCoverageIgnore
+ }
+ } else {
+ $this->method = \STREAM_CRYPTO_METHOD_TLS_CLIENT;
+
+ if (\PHP_VERSION_ID < 70200 && \PHP_VERSION_ID >= 50600) {
+ $this->method |= \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; // @codeCoverageIgnore
+ }
+ }
+ }
+
+ public function enable(Connection $stream)
+ {
+ return $this->toggle($stream, true);
+ }
+
+ public function toggle(Connection $stream, $toggle)
+ {
+ // pause actual stream instance to continue operation on raw stream socket
+ $stream->pause();
+
+ // TODO: add write() event to make sure we're not sending any excessive data
+
+ // cancelling this leaves this stream in an inconsistent state…
+ $deferred = new Deferred(function () {
+ throw new \RuntimeException();
+ });
+
+ // get actual stream socket from stream instance
+ $socket = $stream->stream;
+
+ // get crypto method from context options or use global setting from constructor
+ $method = $this->method;
+ $context = \stream_context_get_options($socket);
+ if (isset($context['ssl']['crypto_method'])) {
+ $method = $context['ssl']['crypto_method'];
+ }
+
+ $that = $this;
+ $toggleCrypto = function () use ($socket, $deferred, $toggle, $method, $that) {
+ $that->toggleCrypto($socket, $deferred, $toggle, $method);
+ };
+
+ $this->loop->addReadStream($socket, $toggleCrypto);
+
+ if (!$this->server) {
+ $toggleCrypto();
+ }
+
+ $loop = $this->loop;
+
+ return $deferred->promise()->then(function () use ($stream, $socket, $loop, $toggle) {
+ $loop->removeReadStream($socket);
+
+ $stream->encryptionEnabled = $toggle;
+ $stream->resume();
+
+ return $stream;
+ }, function($error) use ($stream, $socket, $loop) {
+ $loop->removeReadStream($socket);
+ $stream->resume();
+ throw $error;
+ });
+ }
+
+ public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
+ {
+ $error = null;
+ \set_error_handler(function ($_, $errstr) use (&$error) {
+ $error = \str_replace(array("\r", "\n"), ' ', $errstr);
+
+ // remove useless function name from error message
+ if (($pos = \strpos($error, "): ")) !== false) {
+ $error = \substr($error, $pos + 3);
+ }
+ });
+
+ $result = \stream_socket_enable_crypto($socket, $toggle, $method);
+
+ \restore_error_handler();
+
+ if (true === $result) {
+ $deferred->resolve();
+ } else if (false === $result) {
+ // overwrite callback arguments for PHP7+ only, so they do not show
+ // up in the Exception trace and do not cause a possible cyclic reference.
+ $d = $deferred;
+ $deferred = null;
+
+ if (\feof($socket) || $error === null) {
+ // EOF or failed without error => connection closed during handshake
+ $d->reject(new \UnexpectedValueException(
+ 'Connection lost during TLS handshake (ECONNRESET)',
+ \defined('SOCKET_ECONNRESET') ? \SOCKET_ECONNRESET : 104
+ ));
+ } else {
+ // handshake failed with error message
+ $d->reject(new \UnexpectedValueException(
+ $error
+ ));
+ }
+ } else {
+ // need more data, will retry
+ }
+ }
+}
diff --git a/vendor/react/socket/src/TcpConnector.php b/vendor/react/socket/src/TcpConnector.php
new file mode 100644
index 0000000..a4d3b5b
--- /dev/null
+++ b/vendor/react/socket/src/TcpConnector.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace React\Socket;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+use InvalidArgumentException;
+use RuntimeException;
+
+final class TcpConnector implements ConnectorInterface
+{
+ private $loop;
+ private $context;
+
+ public function __construct(LoopInterface $loop = null, array $context = array())
+ {
+ $this->loop = $loop ?: Loop::get();
+ $this->context = $context;
+ }
+
+ public function connect($uri)
+ {
+ if (\strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ }
+
+ $parts = \parse_url($uri);
+ if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $uri . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ $ip = \trim($parts['host'], '[]');
+ if (@\inet_pton($ip) === false) {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $uri . '" does not contain a valid host IP (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ // use context given in constructor
+ $context = array(
+ 'socket' => $this->context
+ );
+
+ // parse arguments from query component of URI
+ $args = array();
+ if (isset($parts['query'])) {
+ \parse_str($parts['query'], $args);
+ }
+
+ // If an original hostname has been given, use this for TLS setup.
+ // This can happen due to layers of nested connectors, such as a
+ // DnsConnector reporting its original hostname.
+ // These context options are here in case TLS is enabled later on this stream.
+ // If TLS is not enabled later, this doesn't hurt either.
+ if (isset($args['hostname'])) {
+ $context['ssl'] = array(
+ 'SNI_enabled' => true,
+ 'peer_name' => $args['hostname']
+ );
+
+ // Legacy PHP < 5.6 ignores peer_name and requires legacy context options instead.
+ // The SNI_server_name context option has to be set here during construction,
+ // as legacy PHP ignores any values set later.
+ // @codeCoverageIgnoreStart
+ if (\PHP_VERSION_ID < 50600) {
+ $context['ssl'] += array(
+ 'SNI_server_name' => $args['hostname'],
+ 'CN_match' => $args['hostname']
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ // latest versions of PHP no longer accept any other URI components and
+ // HHVM fails to parse URIs with a query but no path, so let's simplify our URI here
+ $remote = 'tcp://' . $parts['host'] . ':' . $parts['port'];
+
+ $stream = @\stream_socket_client(
+ $remote,
+ $errno,
+ $errstr,
+ 0,
+ \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT,
+ \stream_context_create($context)
+ );
+
+ if (false === $stream) {
+ return Promise\reject(new \RuntimeException(
+ 'Connection to ' . $uri . ' failed: ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ ));
+ }
+
+ // wait for connection
+ $loop = $this->loop;
+ return new Promise\Promise(function ($resolve, $reject) use ($loop, $stream, $uri) {
+ $loop->addWriteStream($stream, function ($stream) use ($loop, $resolve, $reject, $uri) {
+ $loop->removeWriteStream($stream);
+
+ // The following hack looks like the only way to
+ // detect connection refused errors with PHP's stream sockets.
+ if (false === \stream_socket_get_name($stream, true)) {
+ // If we reach this point, we know the connection is dead, but we don't know the underlying error condition.
+ // @codeCoverageIgnoreStart
+ if (\function_exists('socket_import_stream')) {
+ // actual socket errno and errstr can be retrieved with ext-sockets on PHP 5.4+
+ $socket = \socket_import_stream($stream);
+ $errno = \socket_get_option($socket, \SOL_SOCKET, \SO_ERROR);
+ $errstr = \socket_strerror($errno);
+ } elseif (\PHP_OS === 'Linux') {
+ // Linux reports socket errno and errstr again when trying to write to the dead socket.
+ // Suppress error reporting to get error message below and close dead socket before rejecting.
+ // This is only known to work on Linux, Mac and Windows are known to not support this.
+ @\fwrite($stream, \PHP_EOL);
+ $error = \error_get_last();
+
+ // fwrite(): send of 2 bytes failed with errno=111 Connection refused
+ \preg_match('/errno=(\d+) (.+)/', $error['message'], $m);
+ $errno = isset($m[1]) ? (int) $m[1] : 0;
+ $errstr = isset($m[2]) ? $m[2] : $error['message'];
+ } else {
+ // Not on Linux and ext-sockets not available? Too bad.
+ $errno = \defined('SOCKET_ECONNREFUSED') ? \SOCKET_ECONNREFUSED : 111;
+ $errstr = 'Connection refused?';
+ }
+ // @codeCoverageIgnoreEnd
+
+ \fclose($stream);
+ $reject(new \RuntimeException(
+ 'Connection to ' . $uri . ' failed: ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ ));
+ } else {
+ $resolve(new Connection($stream, $loop));
+ }
+ });
+ }, function () use ($loop, $stream, $uri) {
+ $loop->removeWriteStream($stream);
+ \fclose($stream);
+
+ // @codeCoverageIgnoreStart
+ // legacy PHP 5.3 sometimes requires a second close call (see tests)
+ if (\PHP_VERSION_ID < 50400 && \is_resource($stream)) {
+ \fclose($stream);
+ }
+ // @codeCoverageIgnoreEnd
+
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' cancelled during TCP/IP handshake (ECONNABORTED)',
+ \defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
+ );
+ });
+ }
+}
diff --git a/vendor/react/socket/src/TcpServer.php b/vendor/react/socket/src/TcpServer.php
new file mode 100644
index 0000000..442af70
--- /dev/null
+++ b/vendor/react/socket/src/TcpServer.php
@@ -0,0 +1,258 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use InvalidArgumentException;
+use RuntimeException;
+
+/**
+ * The `TcpServer` class implements the `ServerInterface` and
+ * is responsible for accepting plaintext TCP/IP connections.
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(8080);
+ * ```
+ *
+ * Whenever a client connects, it will emit a `connection` event with a connection
+ * instance implementing `ConnectionInterface`:
+ *
+ * ```php
+ * $server->on('connection', function (React\Socket\ConnectionInterface $connection) {
+ * echo 'Plaintext connection from ' . $connection->getRemoteAddress() . PHP_EOL;
+ * $connection->write('hello there!' . PHP_EOL);
+ * …
+ * });
+ * ```
+ *
+ * See also the `ServerInterface` for more details.
+ *
+ * @see ServerInterface
+ * @see ConnectionInterface
+ */
+final class TcpServer extends EventEmitter implements ServerInterface
+{
+ private $master;
+ private $loop;
+ private $listening = false;
+
+ /**
+ * Creates a plaintext TCP/IP socket server and starts listening on the given address
+ *
+ * This starts accepting new incoming connections on the given address.
+ * See also the `connection event` documented in the `ServerInterface`
+ * for more details.
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(8080);
+ * ```
+ *
+ * As above, the `$uri` parameter can consist of only a port, in which case the
+ * server will default to listening on the localhost address `127.0.0.1`,
+ * which means it will not be reachable from outside of this system.
+ *
+ * In order to use a random port assignment, you can use the port `0`:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer(0);
+ * $address = $server->getAddress();
+ * ```
+ *
+ * In order to change the host the socket is listening on, you can provide an IP
+ * address through the first parameter provided to the constructor, optionally
+ * preceded by the `tcp://` scheme:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer('192.168.0.1:8080');
+ * ```
+ *
+ * If you want to listen on an IPv6 address, you MUST enclose the host in square
+ * brackets:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer('[::1]:8080');
+ * ```
+ *
+ * If the given URI is invalid, does not contain a port, any other scheme or if it
+ * contains a hostname, it will throw an `InvalidArgumentException`:
+ *
+ * ```php
+ * // throws InvalidArgumentException due to missing port
+ * $server = new React\Socket\TcpServer('127.0.0.1');
+ * ```
+ *
+ * If the given URI appears to be valid, but listening on it fails (such as if port
+ * is already in use or port below 1024 may require root access etc.), it will
+ * throw a `RuntimeException`:
+ *
+ * ```php
+ * $first = new React\Socket\TcpServer(8080);
+ *
+ * // throws RuntimeException because port is already in use
+ * $second = new React\Socket\TcpServer(8080);
+ * ```
+ *
+ * Note that these error conditions may vary depending on your system and/or
+ * configuration.
+ * See the exception message and code for more details about the actual error
+ * condition.
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * Optionally, you can specify [socket context options](https://www.php.net/manual/en/context.socket.php)
+ * for the underlying stream socket resource like this:
+ *
+ * ```php
+ * $server = new React\Socket\TcpServer('[::1]:8080', null, array(
+ * 'backlog' => 200,
+ * 'so_reuseport' => true,
+ * 'ipv6_v6only' => true
+ * ));
+ * ```
+ *
+ * Note that available [socket context options](https://www.php.net/manual/en/context.socket.php),
+ * their defaults and effects of changing these may vary depending on your system
+ * and/or PHP version.
+ * Passing unknown context options has no effect.
+ * The `backlog` context option defaults to `511` unless given explicitly.
+ *
+ * @param string|int $uri
+ * @param ?LoopInterface $loop
+ * @param array $context
+ * @throws InvalidArgumentException if the listening address is invalid
+ * @throws RuntimeException if listening on this address fails (already in use etc.)
+ */
+ public function __construct($uri, LoopInterface $loop = null, array $context = array())
+ {
+ $this->loop = $loop ?: Loop::get();
+
+ // a single port has been given => assume localhost
+ if ((string)(int)$uri === (string)$uri) {
+ $uri = '127.0.0.1:' . $uri;
+ }
+
+ // assume default scheme if none has been given
+ if (\strpos($uri, '://') === false) {
+ $uri = 'tcp://' . $uri;
+ }
+
+ // parse_url() does not accept null ports (random port assignment) => manually remove
+ if (\substr($uri, -2) === ':0') {
+ $parts = \parse_url(\substr($uri, 0, -2));
+ if ($parts) {
+ $parts['port'] = 0;
+ }
+ } else {
+ $parts = \parse_url($uri);
+ }
+
+ // ensure URI contains TCP scheme, host and port
+ if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
+ throw new \InvalidArgumentException(
+ 'Invalid URI "' . $uri . '" given (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ );
+ }
+
+ if (@\inet_pton(\trim($parts['host'], '[]')) === false) {
+ throw new \InvalidArgumentException(
+ 'Given URI "' . $uri . '" does not contain a valid host IP (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ );
+ }
+
+ $this->master = @\stream_socket_server(
+ $uri,
+ $errno,
+ $errstr,
+ \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN,
+ \stream_context_create(array('socket' => $context + array('backlog' => 511)))
+ );
+ if (false === $this->master) {
+ if ($errno === 0) {
+ // PHP does not seem to report errno, so match errno from errstr
+ // @link https://3v4l.org/3qOBl
+ $errno = SocketServer::errno($errstr);
+ }
+
+ throw new \RuntimeException(
+ 'Failed to listen on "' . $uri . '": ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ );
+ }
+ \stream_set_blocking($this->master, false);
+
+ $this->resume();
+ }
+
+ public function getAddress()
+ {
+ if (!\is_resource($this->master)) {
+ return null;
+ }
+
+ $address = \stream_socket_get_name($this->master, false);
+
+ // check if this is an IPv6 address which includes multiple colons but no square brackets
+ $pos = \strrpos($address, ':');
+ if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') {
+ $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1); // @codeCoverageIgnore
+ }
+
+ return 'tcp://' . $address;
+ }
+
+ public function pause()
+ {
+ if (!$this->listening) {
+ return;
+ }
+
+ $this->loop->removeReadStream($this->master);
+ $this->listening = false;
+ }
+
+ public function resume()
+ {
+ if ($this->listening || !\is_resource($this->master)) {
+ return;
+ }
+
+ $that = $this;
+ $this->loop->addReadStream($this->master, function ($master) use ($that) {
+ try {
+ $newSocket = SocketServer::accept($master);
+ } catch (\RuntimeException $e) {
+ $that->emit('error', array($e));
+ return;
+ }
+ $that->handleConnection($newSocket);
+ });
+ $this->listening = true;
+ }
+
+ public function close()
+ {
+ if (!\is_resource($this->master)) {
+ return;
+ }
+
+ $this->pause();
+ \fclose($this->master);
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleConnection($socket)
+ {
+ $this->emit('connection', array(
+ new Connection($socket, $this->loop)
+ ));
+ }
+}
diff --git a/vendor/react/socket/src/TimeoutConnector.php b/vendor/react/socket/src/TimeoutConnector.php
new file mode 100644
index 0000000..332369f
--- /dev/null
+++ b/vendor/react/socket/src/TimeoutConnector.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace React\Socket;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+use React\Promise\Timer\TimeoutException;
+
+final class TimeoutConnector implements ConnectorInterface
+{
+ private $connector;
+ private $timeout;
+ private $loop;
+
+ public function __construct(ConnectorInterface $connector, $timeout, LoopInterface $loop = null)
+ {
+ $this->connector = $connector;
+ $this->timeout = $timeout;
+ $this->loop = $loop ?: Loop::get();
+ }
+
+ public function connect($uri)
+ {
+ return Timer\timeout($this->connector->connect($uri), $this->timeout, $this->loop)->then(null, self::handler($uri));
+ }
+
+ /**
+ * Creates a static rejection handler that reports a proper error message in case of a timeout.
+ *
+ * This uses a private static helper method to ensure this closure is not
+ * bound to this instance and the exception trace does not include a
+ * reference to this instance and its connector stack as a result.
+ *
+ * @param string $uri
+ * @return callable
+ */
+ private static function handler($uri)
+ {
+ return function (\Exception $e) use ($uri) {
+ if ($e instanceof TimeoutException) {
+ throw new \RuntimeException(
+ 'Connection to ' . $uri . ' timed out after ' . $e->getTimeout() . ' seconds (ETIMEDOUT)',
+ \defined('SOCKET_ETIMEDOUT') ? \SOCKET_ETIMEDOUT : 110
+ );
+ }
+
+ throw $e;
+ };
+ }
+}
diff --git a/vendor/react/socket/src/UnixConnector.php b/vendor/react/socket/src/UnixConnector.php
new file mode 100644
index 0000000..513fb51
--- /dev/null
+++ b/vendor/react/socket/src/UnixConnector.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace React\Socket;
+
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use React\Promise;
+use InvalidArgumentException;
+use RuntimeException;
+
+/**
+ * Unix domain socket connector
+ *
+ * Unix domain sockets use atomic operations, so we can as well emulate
+ * async behavior.
+ */
+final class UnixConnector implements ConnectorInterface
+{
+ private $loop;
+
+ public function __construct(LoopInterface $loop = null)
+ {
+ $this->loop = $loop ?: Loop::get();
+ }
+
+ public function connect($path)
+ {
+ if (\strpos($path, '://') === false) {
+ $path = 'unix://' . $path;
+ } elseif (\substr($path, 0, 7) !== 'unix://') {
+ return Promise\reject(new \InvalidArgumentException(
+ 'Given URI "' . $path . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ ));
+ }
+
+ $resource = @\stream_socket_client($path, $errno, $errstr, 1.0);
+
+ if (!$resource) {
+ return Promise\reject(new \RuntimeException(
+ 'Unable to connect to unix domain socket "' . $path . '": ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ ));
+ }
+
+ $connection = new Connection($resource, $this->loop);
+ $connection->unix = true;
+
+ return Promise\resolve($connection);
+ }
+}
diff --git a/vendor/react/socket/src/UnixServer.php b/vendor/react/socket/src/UnixServer.php
new file mode 100644
index 0000000..668e8cb
--- /dev/null
+++ b/vendor/react/socket/src/UnixServer.php
@@ -0,0 +1,154 @@
+<?php
+
+namespace React\Socket;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use InvalidArgumentException;
+use RuntimeException;
+
+/**
+ * The `UnixServer` class implements the `ServerInterface` and
+ * is responsible for accepting plaintext connections on unix domain sockets.
+ *
+ * ```php
+ * $server = new React\Socket\UnixServer('unix:///tmp/app.sock');
+ * ```
+ *
+ * See also the `ServerInterface` for more details.
+ *
+ * @see ServerInterface
+ * @see ConnectionInterface
+ */
+final class UnixServer extends EventEmitter implements ServerInterface
+{
+ private $master;
+ private $loop;
+ private $listening = false;
+
+ /**
+ * Creates a plaintext socket server and starts listening on the given unix socket
+ *
+ * This starts accepting new incoming connections on the given address.
+ * See also the `connection event` documented in the `ServerInterface`
+ * for more details.
+ *
+ * ```php
+ * $server = new React\Socket\UnixServer('unix:///tmp/app.sock');
+ * ```
+ *
+ * This class takes an optional `LoopInterface|null $loop` parameter that can be used to
+ * pass the event loop instance to use for this object. You can use a `null` value
+ * here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
+ * This value SHOULD NOT be given unless you're sure you want to explicitly use a
+ * given event loop instance.
+ *
+ * @param string $path
+ * @param ?LoopInterface $loop
+ * @param array $context
+ * @throws InvalidArgumentException if the listening address is invalid
+ * @throws RuntimeException if listening on this address fails (already in use etc.)
+ */
+ public function __construct($path, LoopInterface $loop = null, array $context = array())
+ {
+ $this->loop = $loop ?: Loop::get();
+
+ if (\strpos($path, '://') === false) {
+ $path = 'unix://' . $path;
+ } elseif (\substr($path, 0, 7) !== 'unix://') {
+ throw new \InvalidArgumentException(
+ 'Given URI "' . $path . '" is invalid (EINVAL)',
+ \defined('SOCKET_EINVAL') ? \SOCKET_EINVAL : 22
+ );
+ }
+
+ $this->master = @\stream_socket_server(
+ $path,
+ $errno,
+ $errstr,
+ \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN,
+ \stream_context_create(array('socket' => $context))
+ );
+ if (false === $this->master) {
+ // PHP does not seem to report errno/errstr for Unix domain sockets (UDS) right now.
+ // This only applies to UDS server sockets, see also https://3v4l.org/NAhpr.
+ // Parse PHP warning message containing unknown error, HHVM reports proper info at least.
+ if ($errno === 0 && $errstr === '') {
+ $error = \error_get_last();
+ if (\preg_match('/\(([^\)]+)\)|\[(\d+)\]: (.*)/', $error['message'], $match)) {
+ $errstr = isset($match[3]) ? $match['3'] : $match[1];
+ $errno = isset($match[2]) ? (int)$match[2] : 0;
+ }
+ }
+
+ throw new \RuntimeException(
+ 'Failed to listen on Unix domain socket "' . $path . '": ' . $errstr . SocketServer::errconst($errno),
+ $errno
+ );
+ }
+ \stream_set_blocking($this->master, 0);
+
+ $this->resume();
+ }
+
+ public function getAddress()
+ {
+ if (!\is_resource($this->master)) {
+ return null;
+ }
+
+ return 'unix://' . \stream_socket_get_name($this->master, false);
+ }
+
+ public function pause()
+ {
+ if (!$this->listening) {
+ return;
+ }
+
+ $this->loop->removeReadStream($this->master);
+ $this->listening = false;
+ }
+
+ public function resume()
+ {
+ if ($this->listening || !is_resource($this->master)) {
+ return;
+ }
+
+ $that = $this;
+ $this->loop->addReadStream($this->master, function ($master) use ($that) {
+ try {
+ $newSocket = SocketServer::accept($master);
+ } catch (\RuntimeException $e) {
+ $that->emit('error', array($e));
+ return;
+ }
+ $that->handleConnection($newSocket);
+ });
+ $this->listening = true;
+ }
+
+ public function close()
+ {
+ if (!\is_resource($this->master)) {
+ return;
+ }
+
+ $this->pause();
+ \fclose($this->master);
+ $this->removeAllListeners();
+ }
+
+ /** @internal */
+ public function handleConnection($socket)
+ {
+ $connection = new Connection($socket, $this->loop);
+ $connection->unix = true;
+
+ $this->emit('connection', array(
+ $connection
+ ));
+ }
+}
diff --git a/vendor/react/stream/LICENSE b/vendor/react/stream/LICENSE
new file mode 100644
index 0000000..d6f8901
--- /dev/null
+++ b/vendor/react/stream/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
+
+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/react/stream/composer.json b/vendor/react/stream/composer.json
new file mode 100644
index 0000000..b235f5a
--- /dev/null
+++ b/vendor/react/stream/composer.json
@@ -0,0 +1,47 @@
+{
+ "name": "react/stream",
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": ["event-driven", "readable", "writable", "stream", "non-blocking", "io", "pipe", "ReactPHP"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "homepage": "https://clue.engineering/",
+ "email": "christian@clue.engineering"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "homepage": "https://wyrihaximus.net/",
+ "email": "reactphp@ceesjankiewiet.nl"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "homepage": "https://sorgalla.com/",
+ "email": "jsorgalla@gmail.com"
+ },
+ {
+ "name": "Chris Boden",
+ "homepage": "https://cboden.dev/",
+ "email": "cboden@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "clue/stream-filter": "~1.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "React\\Tests\\Stream\\": "tests"
+ }
+ }
+}
diff --git a/vendor/react/stream/src/CompositeStream.php b/vendor/react/stream/src/CompositeStream.php
new file mode 100644
index 0000000..dde091d
--- /dev/null
+++ b/vendor/react/stream/src/CompositeStream.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitter;
+
+final class CompositeStream extends EventEmitter implements DuplexStreamInterface
+{
+ private $readable;
+ private $writable;
+ private $closed = false;
+
+ public function __construct(ReadableStreamInterface $readable, WritableStreamInterface $writable)
+ {
+ $this->readable = $readable;
+ $this->writable = $writable;
+
+ if (!$readable->isReadable() || !$writable->isWritable()) {
+ $this->close();
+ return;
+ }
+
+ Util::forwardEvents($this->readable, $this, array('data', 'end', 'error'));
+ Util::forwardEvents($this->writable, $this, array('drain', 'error', 'pipe'));
+
+ $this->readable->on('close', array($this, 'close'));
+ $this->writable->on('close', array($this, 'close'));
+ }
+
+ public function isReadable()
+ {
+ return $this->readable->isReadable();
+ }
+
+ public function pause()
+ {
+ $this->readable->pause();
+ }
+
+ public function resume()
+ {
+ if (!$this->writable->isWritable()) {
+ return;
+ }
+
+ $this->readable->resume();
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ public function isWritable()
+ {
+ return $this->writable->isWritable();
+ }
+
+ public function write($data)
+ {
+ return $this->writable->write($data);
+ }
+
+ public function end($data = null)
+ {
+ $this->readable->pause();
+ $this->writable->end($data);
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+ $this->readable->close();
+ $this->writable->close();
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+}
diff --git a/vendor/react/stream/src/DuplexResourceStream.php b/vendor/react/stream/src/DuplexResourceStream.php
new file mode 100644
index 0000000..c3163c6
--- /dev/null
+++ b/vendor/react/stream/src/DuplexResourceStream.php
@@ -0,0 +1,227 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use InvalidArgumentException;
+
+final class DuplexResourceStream extends EventEmitter implements DuplexStreamInterface
+{
+ private $stream;
+
+ /** @var LoopInterface */
+ private $loop;
+
+ /**
+ * Controls the maximum buffer size in bytes to read at once from the stream.
+ *
+ * This can be a positive number which means that up to X bytes will be read
+ * at once from the underlying stream resource. Note that the actual number
+ * of bytes read may be lower if the stream resource has less than X bytes
+ * currently available.
+ *
+ * This can be `-1` which means read everything available from the
+ * underlying stream resource.
+ * This should read until the stream resource is not readable anymore
+ * (i.e. underlying buffer drained), note that this does not neccessarily
+ * mean it reached EOF.
+ *
+ * @var int
+ */
+ private $bufferSize;
+ private $buffer;
+
+ private $readable = true;
+ private $writable = true;
+ private $closing = false;
+ private $listening = false;
+
+ public function __construct($stream, LoopInterface $loop = null, $readChunkSize = null, WritableStreamInterface $buffer = null)
+ {
+ if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
+ throw new InvalidArgumentException('First parameter must be a valid stream resource');
+ }
+
+ // ensure resource is opened for reading and wrting (fopen mode must contain "+")
+ $meta = \stream_get_meta_data($stream);
+ if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], '+') === false) {
+ throw new InvalidArgumentException('Given stream resource is not opened in read and write mode');
+ }
+
+ // this class relies on non-blocking I/O in order to not interrupt the event loop
+ // e.g. pipes on Windows do not support this: https://bugs.php.net/bug.php?id=47918
+ if (\stream_set_blocking($stream, false) !== true) {
+ throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
+ }
+
+ // Use unbuffered read operations on the underlying stream resource.
+ // Reading chunks from the stream may otherwise leave unread bytes in
+ // PHP's stream buffers which some event loop implementations do not
+ // trigger events on (edge triggered).
+ // This does not affect the default event loop implementation (level
+ // triggered), so we can ignore platforms not supporting this (HHVM).
+ // Pipe streams (such as STDIN) do not seem to require this and legacy
+ // PHP versions cause SEGFAULTs on unbuffered pipe streams, so skip this.
+ if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
+ \stream_set_read_buffer($stream, 0);
+ }
+
+ if ($buffer === null) {
+ $buffer = new WritableResourceStream($stream, $loop);
+ }
+
+ $this->stream = $stream;
+ $this->loop = $loop ?: Loop::get();
+ $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize;
+ $this->buffer = $buffer;
+
+ $that = $this;
+
+ $this->buffer->on('error', function ($error) use ($that) {
+ $that->emit('error', array($error));
+ });
+
+ $this->buffer->on('close', array($this, 'close'));
+
+ $this->buffer->on('drain', function () use ($that) {
+ $that->emit('drain');
+ });
+
+ $this->resume();
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function pause()
+ {
+ if ($this->listening) {
+ $this->loop->removeReadStream($this->stream);
+ $this->listening = false;
+ }
+ }
+
+ public function resume()
+ {
+ if (!$this->listening && $this->readable) {
+ $this->loop->addReadStream($this->stream, array($this, 'handleData'));
+ $this->listening = true;
+ }
+ }
+
+ public function write($data)
+ {
+ if (!$this->writable) {
+ return false;
+ }
+
+ return $this->buffer->write($data);
+ }
+
+ public function close()
+ {
+ if (!$this->writable && !$this->closing) {
+ return;
+ }
+
+ $this->closing = false;
+
+ $this->readable = false;
+ $this->writable = false;
+
+ $this->emit('close');
+ $this->pause();
+ $this->buffer->close();
+ $this->removeAllListeners();
+
+ if (\is_resource($this->stream)) {
+ \fclose($this->stream);
+ }
+ }
+
+ public function end($data = null)
+ {
+ if (!$this->writable) {
+ return;
+ }
+
+ $this->closing = true;
+
+ $this->readable = false;
+ $this->writable = false;
+ $this->pause();
+
+ $this->buffer->end($data);
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ /** @internal */
+ public function handleData($stream)
+ {
+ $error = null;
+ \set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$error) {
+ $error = new \ErrorException(
+ $errstr,
+ 0,
+ $errno,
+ $errfile,
+ $errline
+ );
+ });
+
+ $data = \stream_get_contents($stream, $this->bufferSize);
+
+ \restore_error_handler();
+
+ if ($error !== null) {
+ $this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
+ $this->close();
+ return;
+ }
+
+ if ($data !== '') {
+ $this->emit('data', array($data));
+ } elseif (\feof($this->stream)) {
+ // no data read => we reached the end and close the stream
+ $this->emit('end');
+ $this->close();
+ }
+ }
+
+ /**
+ * Returns whether this is a pipe resource in a legacy environment
+ *
+ * This works around a legacy PHP bug (#61019) that was fixed in PHP 5.4.28+
+ * and PHP 5.5.12+ and newer.
+ *
+ * @param resource $resource
+ * @return bool
+ * @link https://github.com/reactphp/child-process/issues/40
+ *
+ * @codeCoverageIgnore
+ */
+ private function isLegacyPipe($resource)
+ {
+ if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
+ $meta = \stream_get_meta_data($resource);
+
+ if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/vendor/react/stream/src/DuplexStreamInterface.php b/vendor/react/stream/src/DuplexStreamInterface.php
new file mode 100644
index 0000000..631ce31
--- /dev/null
+++ b/vendor/react/stream/src/DuplexStreamInterface.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace React\Stream;
+
+/**
+ * The `DuplexStreamInterface` is responsible for providing an interface for
+ * duplex streams (both readable and writable).
+ *
+ * It builds on top of the existing interfaces for readable and writable streams
+ * and follows the exact same method and event semantics.
+ * If you're new to this concept, you should look into the
+ * `ReadableStreamInterface` and `WritableStreamInterface` first.
+ *
+ * Besides defining a few methods, this interface also implements the
+ * `EventEmitterInterface` which allows you to react to the same events defined
+ * on the `ReadbleStreamInterface` and `WritableStreamInterface`.
+ *
+ * The event callback functions MUST be a valid `callable` that obeys strict
+ * parameter definitions and MUST accept event parameters exactly as documented.
+ * The event callback functions MUST NOT throw an `Exception`.
+ * The return value of the event callback functions will be ignored and has no
+ * effect, so for performance reasons you're recommended to not return any
+ * excessive data structures.
+ *
+ * Every implementation of this interface MUST follow these event semantics in
+ * order to be considered a well-behaving stream.
+ *
+ * > Note that higher-level implementations of this interface may choose to
+ * define additional events with dedicated semantics not defined as part of
+ * this low-level stream specification. Conformance with these event semantics
+ * is out of scope for this interface, so you may also have to refer to the
+ * documentation of such a higher-level implementation.
+ *
+ * @see ReadableStreamInterface
+ * @see WritableStreamInterface
+ */
+interface DuplexStreamInterface extends ReadableStreamInterface, WritableStreamInterface
+{
+}
diff --git a/vendor/react/stream/src/ReadableResourceStream.php b/vendor/react/stream/src/ReadableResourceStream.php
new file mode 100644
index 0000000..1b0b08c
--- /dev/null
+++ b/vendor/react/stream/src/ReadableResourceStream.php
@@ -0,0 +1,179 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+use InvalidArgumentException;
+
+final class ReadableResourceStream extends EventEmitter implements ReadableStreamInterface
+{
+ /**
+ * @var resource
+ */
+ private $stream;
+
+ /** @var LoopInterface */
+ private $loop;
+
+ /**
+ * Controls the maximum buffer size in bytes to read at once from the stream.
+ *
+ * This value SHOULD NOT be changed unless you know what you're doing.
+ *
+ * This can be a positive number which means that up to X bytes will be read
+ * at once from the underlying stream resource. Note that the actual number
+ * of bytes read may be lower if the stream resource has less than X bytes
+ * currently available.
+ *
+ * This can be `-1` which means read everything available from the
+ * underlying stream resource.
+ * This should read until the stream resource is not readable anymore
+ * (i.e. underlying buffer drained), note that this does not neccessarily
+ * mean it reached EOF.
+ *
+ * @var int
+ */
+ private $bufferSize;
+
+ private $closed = false;
+ private $listening = false;
+
+ public function __construct($stream, LoopInterface $loop = null, $readChunkSize = null)
+ {
+ if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
+ throw new InvalidArgumentException('First parameter must be a valid stream resource');
+ }
+
+ // ensure resource is opened for reading (fopen mode must contain "r" or "+")
+ $meta = \stream_get_meta_data($stream);
+ if (isset($meta['mode']) && $meta['mode'] !== '' && \strpos($meta['mode'], 'r') === \strpos($meta['mode'], '+')) {
+ throw new InvalidArgumentException('Given stream resource is not opened in read mode');
+ }
+
+ // this class relies on non-blocking I/O in order to not interrupt the event loop
+ // e.g. pipes on Windows do not support this: https://bugs.php.net/bug.php?id=47918
+ if (\stream_set_blocking($stream, false) !== true) {
+ throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
+ }
+
+ // Use unbuffered read operations on the underlying stream resource.
+ // Reading chunks from the stream may otherwise leave unread bytes in
+ // PHP's stream buffers which some event loop implementations do not
+ // trigger events on (edge triggered).
+ // This does not affect the default event loop implementation (level
+ // triggered), so we can ignore platforms not supporting this (HHVM).
+ // Pipe streams (such as STDIN) do not seem to require this and legacy
+ // PHP versions cause SEGFAULTs on unbuffered pipe streams, so skip this.
+ if (\function_exists('stream_set_read_buffer') && !$this->isLegacyPipe($stream)) {
+ \stream_set_read_buffer($stream, 0);
+ }
+
+ $this->stream = $stream;
+ $this->loop = $loop ?: Loop::get();
+ $this->bufferSize = ($readChunkSize === null) ? 65536 : (int)$readChunkSize;
+
+ $this->resume();
+ }
+
+ public function isReadable()
+ {
+ return !$this->closed;
+ }
+
+ public function pause()
+ {
+ if ($this->listening) {
+ $this->loop->removeReadStream($this->stream);
+ $this->listening = false;
+ }
+ }
+
+ public function resume()
+ {
+ if (!$this->listening && !$this->closed) {
+ $this->loop->addReadStream($this->stream, array($this, 'handleData'));
+ $this->listening = true;
+ }
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->closed = true;
+
+ $this->emit('close');
+ $this->pause();
+ $this->removeAllListeners();
+
+ if (\is_resource($this->stream)) {
+ \fclose($this->stream);
+ }
+ }
+
+ /** @internal */
+ public function handleData()
+ {
+ $error = null;
+ \set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$error) {
+ $error = new \ErrorException(
+ $errstr,
+ 0,
+ $errno,
+ $errfile,
+ $errline
+ );
+ });
+
+ $data = \stream_get_contents($this->stream, $this->bufferSize);
+
+ \restore_error_handler();
+
+ if ($error !== null) {
+ $this->emit('error', array(new \RuntimeException('Unable to read from stream: ' . $error->getMessage(), 0, $error)));
+ $this->close();
+ return;
+ }
+
+ if ($data !== '') {
+ $this->emit('data', array($data));
+ } elseif (\feof($this->stream)) {
+ // no data read => we reached the end and close the stream
+ $this->emit('end');
+ $this->close();
+ }
+ }
+
+ /**
+ * Returns whether this is a pipe resource in a legacy environment
+ *
+ * This works around a legacy PHP bug (#61019) that was fixed in PHP 5.4.28+
+ * and PHP 5.5.12+ and newer.
+ *
+ * @param resource $resource
+ * @return bool
+ * @link https://github.com/reactphp/child-process/issues/40
+ *
+ * @codeCoverageIgnore
+ */
+ private function isLegacyPipe($resource)
+ {
+ if (\PHP_VERSION_ID < 50428 || (\PHP_VERSION_ID >= 50500 && \PHP_VERSION_ID < 50512)) {
+ $meta = \stream_get_meta_data($resource);
+
+ if (isset($meta['stream_type']) && $meta['stream_type'] === 'STDIO') {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/vendor/react/stream/src/ReadableStreamInterface.php b/vendor/react/stream/src/ReadableStreamInterface.php
new file mode 100644
index 0000000..fa3d59c
--- /dev/null
+++ b/vendor/react/stream/src/ReadableStreamInterface.php
@@ -0,0 +1,362 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitterInterface;
+
+/**
+ * The `ReadableStreamInterface` is responsible for providing an interface for
+ * read-only streams and the readable side of duplex streams.
+ *
+ * Besides defining a few methods, this interface also implements the
+ * `EventEmitterInterface` which allows you to react to certain events:
+ *
+ * data event:
+ * The `data` event will be emitted whenever some data was read/received
+ * from this source stream.
+ * The event receives a single mixed argument for incoming data.
+ *
+ * ```php
+ * $stream->on('data', function ($data) {
+ * echo $data;
+ * });
+ * ```
+ *
+ * This event MAY be emitted any number of times, which may be zero times if
+ * this stream does not send any data at all.
+ * It SHOULD not be emitted after an `end` or `close` event.
+ *
+ * The given `$data` argument may be of mixed type, but it's usually
+ * recommended it SHOULD be a `string` value or MAY use a type that allows
+ * representation as a `string` for maximum compatibility.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * will emit the raw (binary) payload data that is received over the wire as
+ * chunks of `string` values.
+ *
+ * Due to the stream-based nature of this, the sender may send any number
+ * of chunks with varying sizes. There are no guarantees that these chunks
+ * will be received with the exact same framing the sender intended to send.
+ * In other words, many lower-level protocols (such as TCP/IP) transfer the
+ * data in chunks that may be anywhere between single-byte values to several
+ * dozens of kilobytes. You may want to apply a higher-level protocol to
+ * these low-level data chunks in order to achieve proper message framing.
+ *
+ * end event:
+ * The `end` event will be emitted once the source stream has successfully
+ * reached the end of the stream (EOF).
+ *
+ * ```php
+ * $stream->on('end', function () {
+ * echo 'END';
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once or never at all, depending on whether
+ * a successful end was detected.
+ * It SHOULD NOT be emitted after a previous `end` or `close` event.
+ * It MUST NOT be emitted if the stream closes due to a non-successful
+ * end, such as after a previous `error` event.
+ *
+ * After the stream is ended, it MUST switch to non-readable mode,
+ * see also `isReadable()`.
+ *
+ * This event will only be emitted if the *end* was reached successfully,
+ * not if the stream was interrupted by an unrecoverable error or explicitly
+ * closed. Not all streams know this concept of a "successful end".
+ * Many use-cases involve detecting when the stream closes (terminates)
+ * instead, in this case you should use the `close` event.
+ * After the stream emits an `end` event, it SHOULD usually be followed by a
+ * `close` event.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * will emit this event if either the remote side closes the connection or
+ * a file handle was successfully read until reaching its end (EOF).
+ *
+ * Note that this event should not be confused with the `end()` method.
+ * This event defines a successful end *reading* from a source stream, while
+ * the `end()` method defines *writing* a successful end to a destination
+ * stream.
+ *
+ * error event:
+ * The `error` event will be emitted once a fatal error occurs, usually while
+ * trying to read from this stream.
+ * The event receives a single `Exception` argument for the error instance.
+ *
+ * ```php
+ * $stream->on('error', function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once the stream detects a fatal error, such
+ * as a fatal transmission error or after an unexpected `data` or premature
+ * `end` event.
+ * It SHOULD NOT be emitted after a previous `error`, `end` or `close` event.
+ * It MUST NOT be emitted if this is not a fatal error condition, such as
+ * a temporary network issue that did not cause any data to be lost.
+ *
+ * After the stream errors, it MUST close the stream and SHOULD thus be
+ * followed by a `close` event and then switch to non-readable mode, see
+ * also `close()` and `isReadable()`.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * only deal with data transmission and do not make assumption about data
+ * boundaries (such as unexpected `data` or premature `end` events).
+ * In other words, many lower-level protocols (such as TCP/IP) may choose
+ * to only emit this for a fatal transmission error once and will then
+ * close (terminate) the stream in response.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the writable side of the stream also implements an `error` event.
+ * In other words, an error may occur while either reading or writing the
+ * stream which should result in the same error processing.
+ *
+ * close event:
+ * The `close` event will be emitted once the stream closes (terminates).
+ *
+ * ```php
+ * $stream->on('close', function () {
+ * echo 'CLOSED';
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once or never at all, depending on whether
+ * the stream ever terminates.
+ * It SHOULD NOT be emitted after a previous `close` event.
+ *
+ * After the stream is closed, it MUST switch to non-readable mode,
+ * see also `isReadable()`.
+ *
+ * Unlike the `end` event, this event SHOULD be emitted whenever the stream
+ * closes, irrespective of whether this happens implicitly due to an
+ * unrecoverable error or explicitly when either side closes the stream.
+ * If you only want to detect a *successful* end, you should use the `end`
+ * event instead.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * will likely choose to emit this event after reading a *successful* `end`
+ * event or after a fatal transmission `error` event.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the writable side of the stream also implements a `close` event.
+ * In other words, after receiving this event, the stream MUST switch into
+ * non-writable AND non-readable mode, see also `isWritable()`.
+ * Note that this event should not be confused with the `end` event.
+ *
+ * The event callback functions MUST be a valid `callable` that obeys strict
+ * parameter definitions and MUST accept event parameters exactly as documented.
+ * The event callback functions MUST NOT throw an `Exception`.
+ * The return value of the event callback functions will be ignored and has no
+ * effect, so for performance reasons you're recommended to not return any
+ * excessive data structures.
+ *
+ * Every implementation of this interface MUST follow these event semantics in
+ * order to be considered a well-behaving stream.
+ *
+ * > Note that higher-level implementations of this interface may choose to
+ * define additional events with dedicated semantics not defined as part of
+ * this low-level stream specification. Conformance with these event semantics
+ * is out of scope for this interface, so you may also have to refer to the
+ * documentation of such a higher-level implementation.
+ *
+ * @see EventEmitterInterface
+ */
+interface ReadableStreamInterface extends EventEmitterInterface
+{
+ /**
+ * Checks whether this stream is in a readable state (not closed already).
+ *
+ * This method can be used to check if the stream still accepts incoming
+ * data events or if it is ended or closed already.
+ * Once the stream is non-readable, no further `data` or `end` events SHOULD
+ * be emitted.
+ *
+ * ```php
+ * assert($stream->isReadable() === false);
+ *
+ * $stream->on('data', assertNeverCalled());
+ * $stream->on('end', assertNeverCalled());
+ * ```
+ *
+ * A successfully opened stream always MUST start in readable mode.
+ *
+ * Once the stream ends or closes, it MUST switch to non-readable mode.
+ * This can happen any time, explicitly through `close()` or
+ * implicitly due to a remote close or an unrecoverable transmission error.
+ * Once a stream has switched to non-readable mode, it MUST NOT transition
+ * back to readable mode.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the writable side of the stream also implements an `isWritable()`
+ * method. Unless this is a half-open duplex stream, they SHOULD usually
+ * have the same return value.
+ *
+ * @return bool
+ */
+ public function isReadable();
+
+ /**
+ * Pauses reading incoming data events.
+ *
+ * Removes the data source file descriptor from the event loop. This
+ * allows you to throttle incoming data.
+ *
+ * Unless otherwise noted, a successfully opened stream SHOULD NOT start
+ * in paused state.
+ *
+ * Once the stream is paused, no futher `data` or `end` events SHOULD
+ * be emitted.
+ *
+ * ```php
+ * $stream->pause();
+ *
+ * $stream->on('data', assertShouldNeverCalled());
+ * $stream->on('end', assertShouldNeverCalled());
+ * ```
+ *
+ * This method is advisory-only, though generally not recommended, the
+ * stream MAY continue emitting `data` events.
+ *
+ * You can continue processing events by calling `resume()` again.
+ *
+ * Note that both methods can be called any number of times, in particular
+ * calling `pause()` more than once SHOULD NOT have any effect.
+ *
+ * @see self::resume()
+ * @return void
+ */
+ public function pause();
+
+ /**
+ * Resumes reading incoming data events.
+ *
+ * Re-attach the data source after a previous `pause()`.
+ *
+ * ```php
+ * $stream->pause();
+ *
+ * Loop::addTimer(1.0, function () use ($stream) {
+ * $stream->resume();
+ * });
+ * ```
+ *
+ * Note that both methods can be called any number of times, in particular
+ * calling `resume()` without a prior `pause()` SHOULD NOT have any effect.
+ *
+ * @see self::pause()
+ * @return void
+ */
+ public function resume();
+
+ /**
+ * Pipes all the data from this readable source into the given writable destination.
+ *
+ * Automatically sends all incoming data to the destination.
+ * Automatically throttles the source based on what the destination can handle.
+ *
+ * ```php
+ * $source->pipe($dest);
+ * ```
+ *
+ * Similarly, you can also pipe an instance implementing `DuplexStreamInterface`
+ * into itself in order to write back all the data that is received.
+ * This may be a useful feature for a TCP/IP echo service:
+ *
+ * ```php
+ * $connection->pipe($connection);
+ * ```
+ *
+ * This method returns the destination stream as-is, which can be used to
+ * set up chains of piped streams:
+ *
+ * ```php
+ * $source->pipe($decodeGzip)->pipe($filterBadWords)->pipe($dest);
+ * ```
+ *
+ * By default, this will call `end()` on the destination stream once the
+ * source stream emits an `end` event. This can be disabled like this:
+ *
+ * ```php
+ * $source->pipe($dest, array('end' => false));
+ * ```
+ *
+ * Note that this only applies to the `end` event.
+ * If an `error` or explicit `close` event happens on the source stream,
+ * you'll have to manually close the destination stream:
+ *
+ * ```php
+ * $source->pipe($dest);
+ * $source->on('close', function () use ($dest) {
+ * $dest->end('BYE!');
+ * });
+ * ```
+ *
+ * If the source stream is not readable (closed state), then this is a NO-OP.
+ *
+ * ```php
+ * $source->close();
+ * $source->pipe($dest); // NO-OP
+ * ```
+ *
+ * If the destinantion stream is not writable (closed state), then this will simply
+ * throttle (pause) the source stream:
+ *
+ * ```php
+ * $dest->close();
+ * $source->pipe($dest); // calls $source->pause()
+ * ```
+ *
+ * Similarly, if the destination stream is closed while the pipe is still
+ * active, it will also throttle (pause) the source stream:
+ *
+ * ```php
+ * $source->pipe($dest);
+ * $dest->close(); // calls $source->pause()
+ * ```
+ *
+ * Once the pipe is set up successfully, the destination stream MUST emit
+ * a `pipe` event with this source stream an event argument.
+ *
+ * @param WritableStreamInterface $dest
+ * @param array $options
+ * @return WritableStreamInterface $dest stream as-is
+ */
+ public function pipe(WritableStreamInterface $dest, array $options = array());
+
+ /**
+ * Closes the stream (forcefully).
+ *
+ * This method can be used to (forcefully) close the stream.
+ *
+ * ```php
+ * $stream->close();
+ * ```
+ *
+ * Once the stream is closed, it SHOULD emit a `close` event.
+ * Note that this event SHOULD NOT be emitted more than once, in particular
+ * if this method is called multiple times.
+ *
+ * After calling this method, the stream MUST switch into a non-readable
+ * mode, see also `isReadable()`.
+ * This means that no further `data` or `end` events SHOULD be emitted.
+ *
+ * ```php
+ * $stream->close();
+ * assert($stream->isReadable() === false);
+ *
+ * $stream->on('data', assertNeverCalled());
+ * $stream->on('end', assertNeverCalled());
+ * ```
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the writable side of the stream also implements a `close()` method.
+ * In other words, after calling this method, the stream MUST switch into
+ * non-writable AND non-readable mode, see also `isWritable()`.
+ * Note that this method should not be confused with the `end()` method.
+ *
+ * @return void
+ * @see WritableStreamInterface::close()
+ */
+ public function close();
+}
diff --git a/vendor/react/stream/src/ThroughStream.php b/vendor/react/stream/src/ThroughStream.php
new file mode 100644
index 0000000..6f73fb8
--- /dev/null
+++ b/vendor/react/stream/src/ThroughStream.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitter;
+use InvalidArgumentException;
+
+/**
+ * The `ThroughStream` implements the
+ * [`DuplexStreamInterface`](#duplexstreaminterface) and will simply pass any data
+ * you write to it through to its readable end.
+ *
+ * ```php
+ * $through = new ThroughStream();
+ * $through->on('data', $this->expectCallableOnceWith('hello'));
+ *
+ * $through->write('hello');
+ * ```
+ *
+ * Similarly, the [`end()` method](#end) will end the stream and emit an
+ * [`end` event](#end-event) and then [`close()`](#close-1) the stream.
+ * The [`close()` method](#close-1) will close the stream and emit a
+ * [`close` event](#close-event).
+ * Accordingly, this is can also be used in a [`pipe()`](#pipe) context like this:
+ *
+ * ```php
+ * $through = new ThroughStream();
+ * $source->pipe($through)->pipe($dest);
+ * ```
+ *
+ * Optionally, its constructor accepts any callable function which will then be
+ * used to *filter* any data written to it. This function receives a single data
+ * argument as passed to the writable side and must return the data as it will be
+ * passed to its readable end:
+ *
+ * ```php
+ * $through = new ThroughStream('strtoupper');
+ * $source->pipe($through)->pipe($dest);
+ * ```
+ *
+ * Note that this class makes no assumptions about any data types. This can be
+ * used to convert data, for example for transforming any structured data into
+ * a newline-delimited JSON (NDJSON) stream like this:
+ *
+ * ```php
+ * $through = new ThroughStream(function ($data) {
+ * return json_encode($data) . PHP_EOL;
+ * });
+ * $through->on('data', $this->expectCallableOnceWith("[2, true]\n"));
+ *
+ * $through->write(array(2, true));
+ * ```
+ *
+ * The callback function is allowed to throw an `Exception`. In this case,
+ * the stream will emit an `error` event and then [`close()`](#close-1) the stream.
+ *
+ * ```php
+ * $through = new ThroughStream(function ($data) {
+ * if (!is_string($data)) {
+ * throw new \UnexpectedValueException('Only strings allowed');
+ * }
+ * return $data;
+ * });
+ * $through->on('error', $this->expectCallableOnce()));
+ * $through->on('close', $this->expectCallableOnce()));
+ * $through->on('data', $this->expectCallableNever()));
+ *
+ * $through->write(2);
+ * ```
+ *
+ * @see WritableStreamInterface::write()
+ * @see WritableStreamInterface::end()
+ * @see DuplexStreamInterface::close()
+ * @see WritableStreamInterface::pipe()
+ */
+final class ThroughStream extends EventEmitter implements DuplexStreamInterface
+{
+ private $readable = true;
+ private $writable = true;
+ private $closed = false;
+ private $paused = false;
+ private $drain = false;
+ private $callback;
+
+ public function __construct($callback = null)
+ {
+ if ($callback !== null && !\is_callable($callback)) {
+ throw new InvalidArgumentException('Invalid transformation callback given');
+ }
+
+ $this->callback = $callback;
+ }
+
+ public function pause()
+ {
+ $this->paused = true;
+ }
+
+ public function resume()
+ {
+ if ($this->drain) {
+ $this->drain = false;
+ $this->emit('drain');
+ }
+ $this->paused = false;
+ }
+
+ public function pipe(WritableStreamInterface $dest, array $options = array())
+ {
+ return Util::pipe($this, $dest, $options);
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function write($data)
+ {
+ if (!$this->writable) {
+ return false;
+ }
+
+ if ($this->callback !== null) {
+ try {
+ $data = \call_user_func($this->callback, $data);
+ } catch (\Exception $e) {
+ $this->emit('error', array($e));
+ $this->close();
+
+ return false;
+ }
+ }
+
+ $this->emit('data', array($data));
+
+ if ($this->paused) {
+ $this->drain = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ public function end($data = null)
+ {
+ if (!$this->writable) {
+ return;
+ }
+
+ if (null !== $data) {
+ $this->write($data);
+
+ // return if write() already caused the stream to close
+ if (!$this->writable) {
+ return;
+ }
+ }
+
+ $this->readable = false;
+ $this->writable = false;
+ $this->paused = true;
+ $this->drain = false;
+
+ $this->emit('end');
+ $this->close();
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ $this->readable = false;
+ $this->writable = false;
+ $this->closed = true;
+ $this->paused = true;
+ $this->drain = false;
+ $this->callback = null;
+
+ $this->emit('close');
+ $this->removeAllListeners();
+ }
+}
diff --git a/vendor/react/stream/src/Util.php b/vendor/react/stream/src/Util.php
new file mode 100644
index 0000000..056b037
--- /dev/null
+++ b/vendor/react/stream/src/Util.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace React\Stream;
+
+final class Util
+{
+ /**
+ * Pipes all the data from the given $source into the $dest
+ *
+ * @param ReadableStreamInterface $source
+ * @param WritableStreamInterface $dest
+ * @param array $options
+ * @return WritableStreamInterface $dest stream as-is
+ * @see ReadableStreamInterface::pipe() for more details
+ */
+ public static function pipe(ReadableStreamInterface $source, WritableStreamInterface $dest, array $options = array())
+ {
+ // source not readable => NO-OP
+ if (!$source->isReadable()) {
+ return $dest;
+ }
+
+ // destination not writable => just pause() source
+ if (!$dest->isWritable()) {
+ $source->pause();
+
+ return $dest;
+ }
+
+ $dest->emit('pipe', array($source));
+
+ // forward all source data events as $dest->write()
+ $source->on('data', $dataer = function ($data) use ($source, $dest) {
+ $feedMore = $dest->write($data);
+
+ if (false === $feedMore) {
+ $source->pause();
+ }
+ });
+ $dest->on('close', function () use ($source, $dataer) {
+ $source->removeListener('data', $dataer);
+ $source->pause();
+ });
+
+ // forward destination drain as $source->resume()
+ $dest->on('drain', $drainer = function () use ($source) {
+ $source->resume();
+ });
+ $source->on('close', function () use ($dest, $drainer) {
+ $dest->removeListener('drain', $drainer);
+ });
+
+ // forward end event from source as $dest->end()
+ $end = isset($options['end']) ? $options['end'] : true;
+ if ($end) {
+ $source->on('end', $ender = function () use ($dest) {
+ $dest->end();
+ });
+ $dest->on('close', function () use ($source, $ender) {
+ $source->removeListener('end', $ender);
+ });
+ }
+
+ return $dest;
+ }
+
+ public static function forwardEvents($source, $target, array $events)
+ {
+ foreach ($events as $event) {
+ $source->on($event, function () use ($event, $target) {
+ $target->emit($event, \func_get_args());
+ });
+ }
+ }
+}
diff --git a/vendor/react/stream/src/WritableResourceStream.php b/vendor/react/stream/src/WritableResourceStream.php
new file mode 100644
index 0000000..1af16b1
--- /dev/null
+++ b/vendor/react/stream/src/WritableResourceStream.php
@@ -0,0 +1,168 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitter;
+use React\EventLoop\Loop;
+use React\EventLoop\LoopInterface;
+
+final class WritableResourceStream extends EventEmitter implements WritableStreamInterface
+{
+ private $stream;
+
+ /** @var LoopInterface */
+ private $loop;
+
+ /**
+ * @var int
+ */
+ private $softLimit;
+
+ /**
+ * @var int
+ */
+ private $writeChunkSize;
+
+ private $listening = false;
+ private $writable = true;
+ private $closed = false;
+ private $data = '';
+
+ public function __construct($stream, LoopInterface $loop = null, $writeBufferSoftLimit = null, $writeChunkSize = null)
+ {
+ if (!\is_resource($stream) || \get_resource_type($stream) !== "stream") {
+ throw new \InvalidArgumentException('First parameter must be a valid stream resource');
+ }
+
+ // ensure resource is opened for writing (fopen mode must contain either of "waxc+")
+ $meta = \stream_get_meta_data($stream);
+ if (isset($meta['mode']) && $meta['mode'] !== '' && \strtr($meta['mode'], 'waxc+', '.....') === $meta['mode']) {
+ throw new \InvalidArgumentException('Given stream resource is not opened in write mode');
+ }
+
+ // this class relies on non-blocking I/O in order to not interrupt the event loop
+ // e.g. pipes on Windows do not support this: https://bugs.php.net/bug.php?id=47918
+ if (\stream_set_blocking($stream, false) !== true) {
+ throw new \RuntimeException('Unable to set stream resource to non-blocking mode');
+ }
+
+ $this->stream = $stream;
+ $this->loop = $loop ?: Loop::get();
+ $this->softLimit = ($writeBufferSoftLimit === null) ? 65536 : (int)$writeBufferSoftLimit;
+ $this->writeChunkSize = ($writeChunkSize === null) ? -1 : (int)$writeChunkSize;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function write($data)
+ {
+ if (!$this->writable) {
+ return false;
+ }
+
+ $this->data .= $data;
+
+ if (!$this->listening && $this->data !== '') {
+ $this->listening = true;
+
+ $this->loop->addWriteStream($this->stream, array($this, 'handleWrite'));
+ }
+
+ return !isset($this->data[$this->softLimit - 1]);
+ }
+
+ public function end($data = null)
+ {
+ if (null !== $data) {
+ $this->write($data);
+ }
+
+ $this->writable = false;
+
+ // close immediately if buffer is already empty
+ // otherwise wait for buffer to flush first
+ if ($this->data === '') {
+ $this->close();
+ }
+ }
+
+ public function close()
+ {
+ if ($this->closed) {
+ return;
+ }
+
+ if ($this->listening) {
+ $this->listening = false;
+ $this->loop->removeWriteStream($this->stream);
+ }
+
+ $this->closed = true;
+ $this->writable = false;
+ $this->data = '';
+
+ $this->emit('close');
+ $this->removeAllListeners();
+
+ if (\is_resource($this->stream)) {
+ \fclose($this->stream);
+ }
+ }
+
+ /** @internal */
+ public function handleWrite()
+ {
+ $error = null;
+ \set_error_handler(function ($_, $errstr) use (&$error) {
+ $error = $errstr;
+ });
+
+ if ($this->writeChunkSize === -1) {
+ $sent = \fwrite($this->stream, $this->data);
+ } else {
+ $sent = \fwrite($this->stream, $this->data, $this->writeChunkSize);
+ }
+
+ \restore_error_handler();
+
+ // Only report errors if *nothing* could be sent and an error has been raised.
+ // Ignore non-fatal warnings if *some* data could be sent.
+ // Any hard (permanent) error will fail to send any data at all.
+ // Sending excessive amounts of data will only flush *some* data and then
+ // report a temporary error (EAGAIN) which we do not raise here in order
+ // to keep the stream open for further tries to write.
+ // Should this turn out to be a permanent error later, it will eventually
+ // send *nothing* and we can detect this.
+ if (($sent === 0 || $sent === false) && $error !== null) {
+ $this->emit('error', array(new \RuntimeException('Unable to write to stream: ' . $error)));
+ $this->close();
+
+ return;
+ }
+
+ $exceeded = isset($this->data[$this->softLimit - 1]);
+ $this->data = (string) \substr($this->data, $sent);
+
+ // buffer has been above limit and is now below limit
+ if ($exceeded && !isset($this->data[$this->softLimit - 1])) {
+ $this->emit('drain');
+ }
+
+ // buffer is now completely empty => stop trying to write
+ if ($this->data === '') {
+ // stop waiting for resource to be writable
+ if ($this->listening) {
+ $this->loop->removeWriteStream($this->stream);
+ $this->listening = false;
+ }
+
+ // buffer is end()ing and now completely empty => close buffer
+ if (!$this->writable) {
+ $this->close();
+ }
+ }
+ }
+}
diff --git a/vendor/react/stream/src/WritableStreamInterface.php b/vendor/react/stream/src/WritableStreamInterface.php
new file mode 100644
index 0000000..9b54680
--- /dev/null
+++ b/vendor/react/stream/src/WritableStreamInterface.php
@@ -0,0 +1,347 @@
+<?php
+
+namespace React\Stream;
+
+use Evenement\EventEmitterInterface;
+
+/**
+ * The `WritableStreamInterface` is responsible for providing an interface for
+ * write-only streams and the writable side of duplex streams.
+ *
+ * Besides defining a few methods, this interface also implements the
+ * `EventEmitterInterface` which allows you to react to certain events:
+ *
+ * drain event:
+ * The `drain` event will be emitted whenever the write buffer became full
+ * previously and is now ready to accept more data.
+ *
+ * ```php
+ * $stream->on('drain', function () use ($stream) {
+ * echo 'Stream is now ready to accept more data';
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once every time the buffer became full
+ * previously and is now ready to accept more data.
+ * In other words, this event MAY be emitted any number of times, which may
+ * be zero times if the buffer never became full in the first place.
+ * This event SHOULD NOT be emitted if the buffer has not become full
+ * previously.
+ *
+ * This event is mostly used internally, see also `write()` for more details.
+ *
+ * pipe event:
+ * The `pipe` event will be emitted whenever a readable stream is `pipe()`d
+ * into this stream.
+ * The event receives a single `ReadableStreamInterface` argument for the
+ * source stream.
+ *
+ * ```php
+ * $stream->on('pipe', function (ReadableStreamInterface $source) use ($stream) {
+ * echo 'Now receiving piped data';
+ *
+ * // explicitly close target if source emits an error
+ * $source->on('error', function () use ($stream) {
+ * $stream->close();
+ * });
+ * });
+ *
+ * $source->pipe($stream);
+ * ```
+ *
+ * This event MUST be emitted once for each readable stream that is
+ * successfully piped into this destination stream.
+ * In other words, this event MAY be emitted any number of times, which may
+ * be zero times if no stream is ever piped into this stream.
+ * This event MUST NOT be emitted if either the source is not readable
+ * (closed already) or this destination is not writable (closed already).
+ *
+ * This event is mostly used internally, see also `pipe()` for more details.
+ *
+ * error event:
+ * The `error` event will be emitted once a fatal error occurs, usually while
+ * trying to write to this stream.
+ * The event receives a single `Exception` argument for the error instance.
+ *
+ * ```php
+ * $stream->on('error', function (Exception $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once the stream detects a fatal error, such
+ * as a fatal transmission error.
+ * It SHOULD NOT be emitted after a previous `error` or `close` event.
+ * It MUST NOT be emitted if this is not a fatal error condition, such as
+ * a temporary network issue that did not cause any data to be lost.
+ *
+ * After the stream errors, it MUST close the stream and SHOULD thus be
+ * followed by a `close` event and then switch to non-writable mode, see
+ * also `close()` and `isWritable()`.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * only deal with data transmission and may choose
+ * to only emit this for a fatal transmission error once and will then
+ * close (terminate) the stream in response.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the readable side of the stream also implements an `error` event.
+ * In other words, an error may occur while either reading or writing the
+ * stream which should result in the same error processing.
+ *
+ * close event:
+ * The `close` event will be emitted once the stream closes (terminates).
+ *
+ * ```php
+ * $stream->on('close', function () {
+ * echo 'CLOSED';
+ * });
+ * ```
+ *
+ * This event SHOULD be emitted once or never at all, depending on whether
+ * the stream ever terminates.
+ * It SHOULD NOT be emitted after a previous `close` event.
+ *
+ * After the stream is closed, it MUST switch to non-writable mode,
+ * see also `isWritable()`.
+ *
+ * This event SHOULD be emitted whenever the stream closes, irrespective of
+ * whether this happens implicitly due to an unrecoverable error or
+ * explicitly when either side closes the stream.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * will likely choose to emit this event after flushing the buffer from
+ * the `end()` method, after receiving a *successful* `end` event or after
+ * a fatal transmission `error` event.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the readable side of the stream also implements a `close` event.
+ * In other words, after receiving this event, the stream MUST switch into
+ * non-writable AND non-readable mode, see also `isReadable()`.
+ * Note that this event should not be confused with the `end` event.
+ *
+ * The event callback functions MUST be a valid `callable` that obeys strict
+ * parameter definitions and MUST accept event parameters exactly as documented.
+ * The event callback functions MUST NOT throw an `Exception`.
+ * The return value of the event callback functions will be ignored and has no
+ * effect, so for performance reasons you're recommended to not return any
+ * excessive data structures.
+ *
+ * Every implementation of this interface MUST follow these event semantics in
+ * order to be considered a well-behaving stream.
+ *
+ * > Note that higher-level implementations of this interface may choose to
+ * define additional events with dedicated semantics not defined as part of
+ * this low-level stream specification. Conformance with these event semantics
+ * is out of scope for this interface, so you may also have to refer to the
+ * documentation of such a higher-level implementation.
+ *
+ * @see EventEmitterInterface
+ * @see DuplexStreamInterface
+ */
+interface WritableStreamInterface extends EventEmitterInterface
+{
+ /**
+ * Checks whether this stream is in a writable state (not closed already).
+ *
+ * This method can be used to check if the stream still accepts writing
+ * any data or if it is ended or closed already.
+ * Writing any data to a non-writable stream is a NO-OP:
+ *
+ * ```php
+ * assert($stream->isWritable() === false);
+ *
+ * $stream->write('end'); // NO-OP
+ * $stream->end('end'); // NO-OP
+ * ```
+ *
+ * A successfully opened stream always MUST start in writable mode.
+ *
+ * Once the stream ends or closes, it MUST switch to non-writable mode.
+ * This can happen any time, explicitly through `end()` or `close()` or
+ * implicitly due to a remote close or an unrecoverable transmission error.
+ * Once a stream has switched to non-writable mode, it MUST NOT transition
+ * back to writable mode.
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the readable side of the stream also implements an `isReadable()`
+ * method. Unless this is a half-open duplex stream, they SHOULD usually
+ * have the same return value.
+ *
+ * @return bool
+ */
+ public function isWritable();
+
+ /**
+ * Write some data into the stream.
+ *
+ * A successful write MUST be confirmed with a boolean `true`, which means
+ * that either the data was written (flushed) immediately or is buffered and
+ * scheduled for a future write. Note that this interface gives you no
+ * control over explicitly flushing the buffered data, as finding the
+ * appropriate time for this is beyond the scope of this interface and left
+ * up to the implementation of this interface.
+ *
+ * Many common streams (such as a TCP/IP connection or file-based stream)
+ * may choose to buffer all given data and schedule a future flush by using
+ * an underlying EventLoop to check when the resource is actually writable.
+ *
+ * If a stream cannot handle writing (or flushing) the data, it SHOULD emit
+ * an `error` event and MAY `close()` the stream if it can not recover from
+ * this error.
+ *
+ * If the internal buffer is full after adding `$data`, then `write()`
+ * SHOULD return `false`, indicating that the caller should stop sending
+ * data until the buffer drains.
+ * The stream SHOULD send a `drain` event once the buffer is ready to accept
+ * more data.
+ *
+ * Similarly, if the the stream is not writable (already in a closed state)
+ * it MUST NOT process the given `$data` and SHOULD return `false`,
+ * indicating that the caller should stop sending data.
+ *
+ * The given `$data` argument MAY be of mixed type, but it's usually
+ * recommended it SHOULD be a `string` value or MAY use a type that allows
+ * representation as a `string` for maximum compatibility.
+ *
+ * Many common streams (such as a TCP/IP connection or a file-based stream)
+ * will only accept the raw (binary) payload data that is transferred over
+ * the wire as chunks of `string` values.
+ *
+ * Due to the stream-based nature of this, the sender may send any number
+ * of chunks with varying sizes. There are no guarantees that these chunks
+ * will be received with the exact same framing the sender intended to send.
+ * In other words, many lower-level protocols (such as TCP/IP) transfer the
+ * data in chunks that may be anywhere between single-byte values to several
+ * dozens of kilobytes. You may want to apply a higher-level protocol to
+ * these low-level data chunks in order to achieve proper message framing.
+ *
+ * @param mixed|string $data
+ * @return bool
+ */
+ public function write($data);
+
+ /**
+ * Successfully ends the stream (after optionally sending some final data).
+ *
+ * This method can be used to successfully end the stream, i.e. close
+ * the stream after sending out all data that is currently buffered.
+ *
+ * ```php
+ * $stream->write('hello');
+ * $stream->write('world');
+ * $stream->end();
+ * ```
+ *
+ * If there's no data currently buffered and nothing to be flushed, then
+ * this method MAY `close()` the stream immediately.
+ *
+ * If there's still data in the buffer that needs to be flushed first, then
+ * this method SHOULD try to write out this data and only then `close()`
+ * the stream.
+ * Once the stream is closed, it SHOULD emit a `close` event.
+ *
+ * Note that this interface gives you no control over explicitly flushing
+ * the buffered data, as finding the appropriate time for this is beyond the
+ * scope of this interface and left up to the implementation of this
+ * interface.
+ *
+ * Many common streams (such as a TCP/IP connection or file-based stream)
+ * may choose to buffer all given data and schedule a future flush by using
+ * an underlying EventLoop to check when the resource is actually writable.
+ *
+ * You can optionally pass some final data that is written to the stream
+ * before ending the stream. If a non-`null` value is given as `$data`, then
+ * this method will behave just like calling `write($data)` before ending
+ * with no data.
+ *
+ * ```php
+ * // shorter version
+ * $stream->end('bye');
+ *
+ * // same as longer version
+ * $stream->write('bye');
+ * $stream->end();
+ * ```
+ *
+ * After calling this method, the stream MUST switch into a non-writable
+ * mode, see also `isWritable()`.
+ * This means that no further writes are possible, so any additional
+ * `write()` or `end()` calls have no effect.
+ *
+ * ```php
+ * $stream->end();
+ * assert($stream->isWritable() === false);
+ *
+ * $stream->write('nope'); // NO-OP
+ * $stream->end(); // NO-OP
+ * ```
+ *
+ * If this stream is a `DuplexStreamInterface`, calling this method SHOULD
+ * also end its readable side, unless the stream supports half-open mode.
+ * In other words, after calling this method, these streams SHOULD switch
+ * into non-writable AND non-readable mode, see also `isReadable()`.
+ * This implies that in this case, the stream SHOULD NOT emit any `data`
+ * or `end` events anymore.
+ * Streams MAY choose to use the `pause()` method logic for this, but
+ * special care may have to be taken to ensure a following call to the
+ * `resume()` method SHOULD NOT continue emitting readable events.
+ *
+ * Note that this method should not be confused with the `close()` method.
+ *
+ * @param mixed|string|null $data
+ * @return void
+ */
+ public function end($data = null);
+
+ /**
+ * Closes the stream (forcefully).
+ *
+ * This method can be used to forcefully close the stream, i.e. close
+ * the stream without waiting for any buffered data to be flushed.
+ * If there's still data in the buffer, this data SHOULD be discarded.
+ *
+ * ```php
+ * $stream->close();
+ * ```
+ *
+ * Once the stream is closed, it SHOULD emit a `close` event.
+ * Note that this event SHOULD NOT be emitted more than once, in particular
+ * if this method is called multiple times.
+ *
+ * After calling this method, the stream MUST switch into a non-writable
+ * mode, see also `isWritable()`.
+ * This means that no further writes are possible, so any additional
+ * `write()` or `end()` calls have no effect.
+ *
+ * ```php
+ * $stream->close();
+ * assert($stream->isWritable() === false);
+ *
+ * $stream->write('nope'); // NO-OP
+ * $stream->end(); // NO-OP
+ * ```
+ *
+ * Note that this method should not be confused with the `end()` method.
+ * Unlike the `end()` method, this method does not take care of any existing
+ * buffers and simply discards any buffer contents.
+ * Likewise, this method may also be called after calling `end()` on a
+ * stream in order to stop waiting for the stream to flush its final data.
+ *
+ * ```php
+ * $stream->end();
+ * Loop::addTimer(1.0, function () use ($stream) {
+ * $stream->close();
+ * });
+ * ```
+ *
+ * If this stream is a `DuplexStreamInterface`, you should also notice
+ * how the readable side of the stream also implements a `close()` method.
+ * In other words, after calling this method, the stream MUST switch into
+ * non-writable AND non-readable mode, see also `isReadable()`.
+ *
+ * @return void
+ * @see ReadableStreamInterface::close()
+ */
+ public function close();
+}
diff --git a/vendor/ringcentral/psr7/LICENSE b/vendor/ringcentral/psr7/LICENSE
new file mode 100644
index 0000000..581d95f
--- /dev/null
+++ b/vendor/ringcentral/psr7/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
+
+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/ringcentral/psr7/composer.json b/vendor/ringcentral/psr7/composer.json
new file mode 100644
index 0000000..4955053
--- /dev/null
+++ b/vendor/ringcentral/psr7/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "ringcentral/psr7",
+ "type": "library",
+ "description": "PSR-7 message implementation",
+ "keywords": ["message", "stream", "http", "uri"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "psr/http-message": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "RingCentral\\Psr7\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/AppendStream.php b/vendor/ringcentral/psr7/src/AppendStream.php
new file mode 100644
index 0000000..8b8df6f
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/AppendStream.php
@@ -0,0 +1,233 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Reads from multiple streams, one after the other.
+ *
+ * This is a read-only stream decorator.
+ */
+class AppendStream implements StreamInterface
+{
+ /** @var StreamInterface[] Streams being decorated */
+ private $streams = array();
+
+ private $seekable = true;
+ private $current = 0;
+ private $pos = 0;
+ private $detached = false;
+
+ /**
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
+ * be readable.
+ */
+ public function __construct(array $streams = array())
+ {
+ foreach ($streams as $stream) {
+ $this->addStream($stream);
+ }
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ /**
+ * Add a stream to the AppendStream
+ *
+ * @param StreamInterface $stream Stream to append. Must be readable.
+ *
+ * @throws \InvalidArgumentException if the stream is not readable
+ */
+ public function addStream(StreamInterface $stream)
+ {
+ if (!$stream->isReadable()) {
+ throw new \InvalidArgumentException('Each stream must be readable');
+ }
+
+ // The stream is only seekable if all streams are seekable
+ if (!$stream->isSeekable()) {
+ $this->seekable = false;
+ }
+
+ $this->streams[] = $stream;
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * Closes each attached stream.
+ *
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->pos = $this->current = 0;
+
+ foreach ($this->streams as $stream) {
+ $stream->close();
+ }
+
+ $this->streams = array();
+ }
+
+ /**
+ * Detaches each attached stream
+ *
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $this->close();
+ $this->detached = true;
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Tries to calculate the size by adding the size of each stream.
+ *
+ * If any of the streams do not return a valid number, then the size of the
+ * append stream cannot be determined and null is returned.
+ *
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ $size = 0;
+
+ foreach ($this->streams as $stream) {
+ $s = $stream->getSize();
+ if ($s === null) {
+ return null;
+ }
+ $size += $s;
+ }
+
+ return $size;
+ }
+
+ public function eof()
+ {
+ return !$this->streams ||
+ ($this->current >= count($this->streams) - 1 &&
+ $this->streams[$this->current]->eof());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ /**
+ * Attempts to seek to the given position. Only supports SEEK_SET.
+ *
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('This AppendStream is not seekable');
+ } elseif ($whence !== SEEK_SET) {
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
+ }
+
+ $this->pos = $this->current = 0;
+
+ // Rewind each stream
+ foreach ($this->streams as $i => $stream) {
+ try {
+ $stream->rewind();
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Unable to seek stream '
+ . $i . ' of the AppendStream', 0, $e);
+ }
+ }
+
+ // Seek to the actual position by reading from each stream
+ while ($this->pos < $offset && !$this->eof()) {
+ $result = $this->read(min(8096, $offset - $this->pos));
+ if ($result === '') {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads from all of the appended streams until the length is met or EOF.
+ *
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ $buffer = '';
+ $total = count($this->streams) - 1;
+ $remaining = $length;
+ $progressToNext = false;
+
+ while ($remaining > 0) {
+
+ // Progress to the next stream if needed.
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
+ $progressToNext = false;
+ if ($this->current === $total) {
+ break;
+ }
+ $this->current++;
+ }
+
+ $result = $this->streams[$this->current]->read($remaining);
+
+ // Using a loose comparison here to match on '', false, and null
+ if ($result == null) {
+ $progressToNext = true;
+ continue;
+ }
+
+ $buffer .= $result;
+ $remaining = $length - strlen($buffer);
+ }
+
+ $this->pos += strlen($buffer);
+
+ return $buffer;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to an AppendStream');
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key ? null : array();
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/BufferStream.php b/vendor/ringcentral/psr7/src/BufferStream.php
new file mode 100644
index 0000000..a1e236d
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/BufferStream.php
@@ -0,0 +1,137 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a buffer stream that can be written to to fill a buffer, and read
+ * from to remove bytes from the buffer.
+ *
+ * This stream returns a "hwm" metadata value that tells upstream consumers
+ * what the configured high water mark of the stream is, or the maximum
+ * preferred size of the buffer.
+ */
+class BufferStream implements StreamInterface
+{
+ private $hwm;
+ private $buffer = '';
+
+ /**
+ * @param int $hwm High water mark, representing the preferred maximum
+ * buffer size. If the size of the buffer exceeds the high
+ * water mark, then calls to write will continue to succeed
+ * but will return false to inform writers to slow down
+ * until the buffer has been drained by reading from it.
+ */
+ public function __construct($hwm = 16384)
+ {
+ $this->hwm = $hwm;
+ }
+
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ public function getContents()
+ {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ }
+
+ public function detach()
+ {
+ $this->close();
+ }
+
+ public function getSize()
+ {
+ return strlen($this->buffer);
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return true;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a BufferStream');
+ }
+
+ public function eof()
+ {
+ return strlen($this->buffer) === 0;
+ }
+
+ public function tell()
+ {
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
+ }
+
+ /**
+ * Reads data from the buffer.
+ */
+ public function read($length)
+ {
+ $currentLength = strlen($this->buffer);
+
+ if ($length >= $currentLength) {
+ // No need to slice the buffer because we don't have enough data.
+ $result = $this->buffer;
+ $this->buffer = '';
+ } else {
+ // Slice up the result to provide a subset of the buffer.
+ $result = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Writes data to the buffer.
+ */
+ public function write($string)
+ {
+ $this->buffer .= $string;
+
+ // TODO: What should happen here?
+ if (strlen($this->buffer) >= $this->hwm) {
+ return false;
+ }
+
+ return strlen($string);
+ }
+
+ public function getMetadata($key = null)
+ {
+ if ($key == 'hwm') {
+ return $this->hwm;
+ }
+
+ return $key ? null : array();
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/CachingStream.php b/vendor/ringcentral/psr7/src/CachingStream.php
new file mode 100644
index 0000000..ce3aca8
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/CachingStream.php
@@ -0,0 +1,135 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that can cache previously read bytes from a sequentially
+ * read stream.
+ */
+class CachingStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ /** @var StreamInterface Stream being wrapped */
+ private $remoteStream;
+
+ /** @var int Number of bytes to skip reading due to a write on the buffer */
+ private $skipReadBytes = 0;
+
+ /**
+ * We will treat the buffer object as the body of the stream
+ *
+ * @param StreamInterface $stream Stream to cache
+ * @param StreamInterface $target Optionally specify where data is cached
+ */
+ public function __construct(
+ StreamInterface $stream,
+ StreamInterface $target = null
+ ) {
+ $this->remoteStream = $stream;
+ parent::__construct($target ?: new Stream(fopen('php://temp', 'r+')));
+ }
+
+ public function getSize()
+ {
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->tell();
+ } elseif ($whence == SEEK_END) {
+ $size = $this->remoteStream->getSize();
+ if ($size === null) {
+ $size = $this->cacheEntireStream();
+ }
+ // Because 0 is the first byte, we seek to size - 1.
+ $byte = $size - 1 - $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid whence');
+ }
+
+ $diff = $byte - $this->stream->getSize();
+
+ if ($diff > 0) {
+ // If the seek byte is greater the number of read bytes, then read
+ // the difference of bytes to cache the bytes and inherently seek.
+ $this->read($diff);
+ } else {
+ // We can just do a normal seek since we've already seen this byte.
+ $this->stream->seek($byte);
+ }
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->stream->read($length);
+ $remaining = $length - strlen($data);
+
+ // More data was requested so read from the remote stream
+ if ($remaining) {
+ // If data was written to the buffer in a position that would have
+ // been filled from the remote stream, then we must skip bytes on
+ // the remote stream to emulate overwriting bytes from that
+ // position. This mimics the behavior of other PHP stream wrappers.
+ $remoteData = $this->remoteStream->read(
+ $remaining + $this->skipReadBytes
+ );
+
+ if ($this->skipReadBytes) {
+ $len = strlen($remoteData);
+ $remoteData = substr($remoteData, $this->skipReadBytes);
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
+ }
+
+ $data .= $remoteData;
+ $this->stream->write($remoteData);
+ }
+
+ return $data;
+ }
+
+ public function write($string)
+ {
+ // When appending to the end of the currently read stream, you'll want
+ // to skip bytes from being read from the remote stream to emulate
+ // other stream wrappers. Basically replacing bytes of data of a fixed
+ // length.
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->stream->write($string);
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof() && $this->remoteStream->eof();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ $this->remoteStream->close() && $this->stream->close();
+ }
+
+ private function cacheEntireStream()
+ {
+ $target = new FnStream(array('write' => 'strlen'));
+ copy_to_stream($this, $target);
+
+ return $this->tell();
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/DroppingStream.php b/vendor/ringcentral/psr7/src/DroppingStream.php
new file mode 100644
index 0000000..3a34d38
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/DroppingStream.php
@@ -0,0 +1,41 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that begins dropping data once the size of the underlying
+ * stream becomes too full.
+ */
+class DroppingStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ private $maxLength;
+
+ /**
+ * @param StreamInterface $stream Underlying stream to decorate.
+ * @param int $maxLength Maximum size before dropping data.
+ */
+ public function __construct(StreamInterface $stream, $maxLength)
+ {
+ parent::__construct($stream);
+ $this->maxLength = $maxLength;
+ }
+
+ public function write($string)
+ {
+ $diff = $this->maxLength - $this->stream->getSize();
+
+ // Begin returning 0 when the underlying stream is too large.
+ if ($diff <= 0) {
+ return 0;
+ }
+
+ // Write the stream or a subset of the stream if needed.
+ if (strlen($string) < $diff) {
+ return $this->stream->write($string);
+ }
+
+ return $this->stream->write(substr($string, 0, $diff));
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/FnStream.php b/vendor/ringcentral/psr7/src/FnStream.php
new file mode 100644
index 0000000..f78dc8b
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/FnStream.php
@@ -0,0 +1,163 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Compose stream implementations based on a hash of functions.
+ *
+ * Allows for easy testing and extension of a provided stream without needing
+ * to create a concrete class for a simple extension point.
+ * @property callable _fn___toString
+ * @property callable _fn_close
+ * @property callable _fn_detach
+ * @property callable _fn_getSize
+ * @property callable _fn_tell
+ * @property callable _fn_isSeekable
+ * @property callable _fn_rewind
+ * @property callable _fn_seek
+ * @property callable _fn_isWritable
+ * @property callable _fn_write
+ * @property callable _fn_isReadable
+ * @property callable _fn_read
+ * @property callable _fn_getContents
+ * @property callable _fn_getMetadata
+ */
+class FnStream implements StreamInterface
+{
+ /** @var array */
+ private $methods;
+
+ /** @var array Methods that must be implemented in the given array */
+ private static $slots = array('__toString', 'close', 'detach', 'rewind',
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
+ 'isReadable', 'read', 'getContents', 'getMetadata');
+
+ /**
+ * @param array $methods Hash of method name to a callable.
+ */
+ public function __construct(array $methods)
+ {
+ $this->methods = $methods;
+
+ // Create the functions on the class
+ foreach ($methods as $name => $fn) {
+ $this->{'_fn_' . $name} = $fn;
+ }
+ }
+
+ /**
+ * Lazily determine which methods are not implemented.
+ * @throws \BadMethodCallException
+ */
+ public function __get($name)
+ {
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
+ . '() is not implemented in the FnStream');
+ }
+
+ /**
+ * The close method is called on the underlying stream only if possible.
+ */
+ public function __destruct()
+ {
+ if (isset($this->_fn_close)) {
+ call_user_func($this->_fn_close);
+ }
+ }
+
+ /**
+ * Adds custom functionality to an underlying stream by intercepting
+ * specific method calls.
+ *
+ * @param StreamInterface $stream Stream to decorate
+ * @param array $methods Hash of method name to a closure
+ *
+ * @return FnStream
+ */
+ public static function decorate(StreamInterface $stream, array $methods)
+ {
+ // If any of the required methods were not provided, then simply
+ // proxy to the decorated stream.
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
+ $methods[$diff] = array($stream, $diff);
+ }
+
+ return new self($methods);
+ }
+
+ public function __toString()
+ {
+ return call_user_func($this->_fn___toString);
+ }
+
+ public function close()
+ {
+ return call_user_func($this->_fn_close);
+ }
+
+ public function detach()
+ {
+ return call_user_func($this->_fn_detach);
+ }
+
+ public function getSize()
+ {
+ return call_user_func($this->_fn_getSize);
+ }
+
+ public function tell()
+ {
+ return call_user_func($this->_fn_tell);
+ }
+
+ public function eof()
+ {
+ return call_user_func($this->_fn_eof);
+ }
+
+ public function isSeekable()
+ {
+ return call_user_func($this->_fn_isSeekable);
+ }
+
+ public function rewind()
+ {
+ call_user_func($this->_fn_rewind);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ call_user_func($this->_fn_seek, $offset, $whence);
+ }
+
+ public function isWritable()
+ {
+ return call_user_func($this->_fn_isWritable);
+ }
+
+ public function write($string)
+ {
+ return call_user_func($this->_fn_write, $string);
+ }
+
+ public function isReadable()
+ {
+ return call_user_func($this->_fn_isReadable);
+ }
+
+ public function read($length)
+ {
+ return call_user_func($this->_fn_read, $length);
+ }
+
+ public function getContents()
+ {
+ return call_user_func($this->_fn_getContents);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return call_user_func($this->_fn_getMetadata, $key);
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/InflateStream.php b/vendor/ringcentral/psr7/src/InflateStream.php
new file mode 100644
index 0000000..c718002
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/InflateStream.php
@@ -0,0 +1,27 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
+ *
+ * This stream decorator skips the first 10 bytes of the given stream to remove
+ * the gzip header, converts the provided stream to a PHP stream resource,
+ * then appends the zlib.inflate filter. The stream is then converted back
+ * to a Guzzle stream resource to be used as a Guzzle stream.
+ *
+ * @link http://tools.ietf.org/html/rfc1952
+ * @link http://php.net/manual/en/filters.compression.php
+ */
+class InflateStream extends StreamDecoratorTrait implements StreamInterface
+{
+ public function __construct(StreamInterface $stream)
+ {
+ // Skip the first 10 bytes
+ $stream = new LimitStream($stream, -1, 10);
+ $resource = StreamWrapper::getResource($stream);
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
+ parent::__construct(new Stream($resource));
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/LazyOpenStream.php b/vendor/ringcentral/psr7/src/LazyOpenStream.php
new file mode 100644
index 0000000..d8768f7
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/LazyOpenStream.php
@@ -0,0 +1,39 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Lazily reads or writes to a file that is opened only after an IO operation
+ * take place on the stream.
+ */
+class LazyOpenStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ /** @var string File to open */
+ private $filename;
+
+ /** @var string $mode */
+ private $mode;
+
+ /**
+ * @param string $filename File to lazily open
+ * @param string $mode fopen mode to use when opening the stream
+ */
+ public function __construct($filename, $mode)
+ {
+ $this->filename = $filename;
+ $this->mode = $mode;
+ parent::__construct();
+ }
+
+ /**
+ * Creates the underlying stream lazily when required.
+ *
+ * @return StreamInterface
+ */
+ protected function createStream()
+ {
+ return stream_for(try_fopen($this->filename, $this->mode));
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/LimitStream.php b/vendor/ringcentral/psr7/src/LimitStream.php
new file mode 100644
index 0000000..57eeca9
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/LimitStream.php
@@ -0,0 +1,154 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+
+/**
+ * Decorator used to return only a subset of a stream
+ */
+class LimitStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ /** @var int Offset to start reading from */
+ private $offset;
+
+ /** @var int Limit the number of bytes that can be read */
+ private $limit;
+
+ /**
+ * @param StreamInterface $stream Stream to wrap
+ * @param int $limit Total number of bytes to allow to be read
+ * from the stream. Pass -1 for no limit.
+ * @param int|null $offset Position to seek to before reading (only
+ * works on seekable streams).
+ */
+ public function __construct(
+ StreamInterface $stream,
+ $limit = -1,
+ $offset = 0
+ ) {
+ parent::__construct($stream);
+ $this->setLimit($limit);
+ $this->setOffset($offset);
+ }
+
+ public function eof()
+ {
+ // Always return true if the underlying stream is EOF
+ if ($this->stream->eof()) {
+ return true;
+ }
+
+ // No limit and the underlying stream is not at EOF
+ if ($this->limit == -1) {
+ return false;
+ }
+
+ return $this->stream->tell() >= $this->offset + $this->limit;
+ }
+
+ /**
+ * Returns the size of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === ($length = $this->stream->getSize())) {
+ return null;
+ } elseif ($this->limit == -1) {
+ return $length - $this->offset;
+ } else {
+ return min($this->limit, $length - $this->offset);
+ }
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited stream
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence !== SEEK_SET || $offset < 0) {
+ throw new \RuntimeException(sprintf(
+ 'Cannot seek to offset % with whence %s',
+ $offset,
+ $whence
+ ));
+ }
+
+ $offset += $this->offset;
+
+ if ($this->limit !== -1) {
+ if ($offset > $this->offset + $this->limit) {
+ $offset = $this->offset + $this->limit;
+ }
+ }
+
+ $this->stream->seek($offset);
+ }
+
+ /**
+ * Give a relative tell()
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell() - $this->offset;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @throws \RuntimeException if the stream cannot be seeked.
+ */
+ public function setOffset($offset)
+ {
+ $current = $this->stream->tell();
+
+ if ($current !== $offset) {
+ // If the stream cannot seek to the offset position, then read to it
+ if ($this->stream->isSeekable()) {
+ $this->stream->seek($offset);
+ } elseif ($current > $offset) {
+ throw new \RuntimeException("Could not seek to stream offset $offset");
+ } else {
+ $this->stream->read($offset - $current);
+ }
+ }
+
+ $this->offset = $offset;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the
+ * stream.
+ *
+ * @param int $limit Number of bytes to allow to be read from the stream.
+ * Use -1 for no limit.
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function read($length)
+ {
+ if ($this->limit == -1) {
+ return $this->stream->read($length);
+ }
+
+ // Check if the current position is less than the total allowed
+ // bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte
+ // limit is not exceeded
+ return $this->stream->read(min($remaining, $length));
+ }
+
+ return '';
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/MessageTrait.php b/vendor/ringcentral/psr7/src/MessageTrait.php
new file mode 100644
index 0000000..9330bcb
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/MessageTrait.php
@@ -0,0 +1,167 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Trait implementing functionality common to requests and responses.
+ */
+abstract class MessageTrait
+{
+ /** @var array Cached HTTP header collection with lowercase key to values */
+ protected $headers = array();
+
+ /** @var array Actual key to list of values per header. */
+ protected $headerLines = array();
+
+ /** @var string */
+ protected $protocol = '1.1';
+
+ /** @var StreamInterface */
+ protected $stream;
+
+ public function getProtocolVersion()
+ {
+ return $this->protocol;
+ }
+
+ public function withProtocolVersion($version)
+ {
+ if ($this->protocol === $version) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->protocol = $version;
+ return $new;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headerLines;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headers[strtolower($header)]);
+ }
+
+ public function getHeader($header)
+ {
+ $name = strtolower($header);
+ return isset($this->headers[$name]) ? $this->headers[$name] : array();
+ }
+
+ public function getHeaderLine($header)
+ {
+ return implode(', ', $this->getHeader($header));
+ }
+
+ public function withHeader($header, $value)
+ {
+ $new = clone $this;
+ $header = trim($header);
+ $name = strtolower($header);
+
+ if (!is_array($value)) {
+ $new->headers[$name] = array(trim($value));
+ } else {
+ $new->headers[$name] = $value;
+ foreach ($new->headers[$name] as &$v) {
+ $v = trim($v);
+ }
+ }
+
+ // Remove the header lines.
+ foreach (array_keys($new->headerLines) as $key) {
+ if (strtolower($key) === $name) {
+ unset($new->headerLines[$key]);
+ }
+ }
+
+ // Add the header line.
+ $new->headerLines[$header] = $new->headers[$name];
+
+ return $new;
+ }
+
+ public function withAddedHeader($header, $value)
+ {
+ if (!$this->hasHeader($header)) {
+ return $this->withHeader($header, $value);
+ }
+
+ $header = trim($header);
+ $name = strtolower($header);
+
+ $value = (array) $value;
+ foreach ($value as &$v) {
+ $v = trim($v);
+ }
+
+ $new = clone $this;
+ $new->headers[$name] = array_merge($new->headers[$name], $value);
+ $new->headerLines[$header] = array_merge($new->headerLines[$header], $value);
+
+ return $new;
+ }
+
+ public function withoutHeader($header)
+ {
+ if (!$this->hasHeader($header)) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $name = strtolower($header);
+ unset($new->headers[$name]);
+
+ foreach (array_keys($new->headerLines) as $key) {
+ if (strtolower($key) === $name) {
+ unset($new->headerLines[$key]);
+ }
+ }
+
+ return $new;
+ }
+
+ public function getBody()
+ {
+ if (!$this->stream) {
+ $this->stream = stream_for('');
+ }
+
+ return $this->stream;
+ }
+
+ public function withBody(StreamInterface $body)
+ {
+ if ($body === $this->stream) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->stream = $body;
+ return $new;
+ }
+
+ protected function setHeaders(array $headers)
+ {
+ $this->headerLines = $this->headers = array();
+ foreach ($headers as $header => $value) {
+ $header = trim($header);
+ $name = strtolower($header);
+ if (!is_array($value)) {
+ $value = trim($value);
+ $this->headers[$name][] = $value;
+ $this->headerLines[$header][] = $value;
+ } else {
+ foreach ($value as $v) {
+ $v = trim($v);
+ $this->headers[$name][] = $v;
+ $this->headerLines[$header][] = $v;
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/MultipartStream.php b/vendor/ringcentral/psr7/src/MultipartStream.php
new file mode 100644
index 0000000..8c5e5bc
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/MultipartStream.php
@@ -0,0 +1,152 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream that when read returns bytes for a streaming multipart or
+ * multipart/form-data stream.
+ */
+class MultipartStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ private $boundary;
+
+ /**
+ * @param array $elements Array of associative arrays, each containing a
+ * required "name" key mapping to the form field,
+ * name, a required "contents" key mapping to a
+ * StreamInterface/resource/string, an optional
+ * "headers" associative array of custom headers,
+ * and an optional "filename" key mapping to a
+ * string to send as the filename in the part.
+ * @param string $boundary You can optionally provide a specific boundary
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(array $elements = array(), $boundary = null)
+ {
+ $this->boundary = $boundary ?: uniqid();
+ parent::__construct($this->createStream($elements));
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the headers needed before transferring the content of a POST file
+ */
+ private function getHeaders(array $headers)
+ {
+ $str = '';
+ foreach ($headers as $key => $value) {
+ $str .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
+ }
+
+ /**
+ * Create the aggregate stream that will be used to upload the POST data
+ */
+ protected function createStream(array $elements)
+ {
+ $stream = new AppendStream();
+
+ foreach ($elements as $element) {
+ $this->addElement($stream, $element);
+ }
+
+ // Add the trailing boundary with CRLF
+ $stream->addStream(stream_for("--{$this->boundary}--\r\n"));
+
+ return $stream;
+ }
+
+ private function addElement(AppendStream $stream, array $element)
+ {
+ foreach (array('contents', 'name') as $key) {
+ if (!array_key_exists($key, $element)) {
+ throw new \InvalidArgumentException("A '{$key}' key is required");
+ }
+ }
+
+ $element['contents'] = stream_for($element['contents']);
+
+ if (empty($element['filename'])) {
+ $uri = $element['contents']->getMetadata('uri');
+ if (substr($uri, 0, 6) !== 'php://') {
+ $element['filename'] = $uri;
+ }
+ }
+
+ list($body, $headers) = $this->createElement(
+ $element['name'],
+ $element['contents'],
+ isset($element['filename']) ? $element['filename'] : null,
+ isset($element['headers']) ? $element['headers'] : array()
+ );
+
+ $stream->addStream(stream_for($this->getHeaders($headers)));
+ $stream->addStream($body);
+ $stream->addStream(stream_for("\r\n"));
+ }
+
+ /**
+ * @return array
+ */
+ private function createElement($name, $stream, $filename, array $headers)
+ {
+ // Set a default content-disposition header if one was no provided
+ $disposition = $this->getHeader($headers, 'content-disposition');
+ if (!$disposition) {
+ $headers['Content-Disposition'] = $filename
+ ? sprintf('form-data; name="%s"; filename="%s"',
+ $name,
+ basename($filename))
+ : "form-data; name=\"{$name}\"";
+ }
+
+ // Set a default content-length header if one was no provided
+ $length = $this->getHeader($headers, 'content-length');
+ if (!$length) {
+ if ($length = $stream->getSize()) {
+ $headers['Content-Length'] = (string) $length;
+ }
+ }
+
+ // Set a default Content-Type if one was not supplied
+ $type = $this->getHeader($headers, 'content-type');
+ if (!$type && $filename) {
+ if ($type = mimetype_from_filename($filename)) {
+ $headers['Content-Type'] = $type;
+ }
+ }
+
+ return array($stream, $headers);
+ }
+
+ private function getHeader(array $headers, $key)
+ {
+ $lowercaseHeader = strtolower($key);
+ foreach ($headers as $k => $v) {
+ if (strtolower($k) === $lowercaseHeader) {
+ return $v;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/NoSeekStream.php b/vendor/ringcentral/psr7/src/NoSeekStream.php
new file mode 100644
index 0000000..328fdda
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/NoSeekStream.php
@@ -0,0 +1,21 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that prevents a stream from being seeked
+ */
+class NoSeekStream extends StreamDecoratorTrait implements StreamInterface
+{
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a NoSeekStream');
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/PumpStream.php b/vendor/ringcentral/psr7/src/PumpStream.php
new file mode 100644
index 0000000..0cb8510
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/PumpStream.php
@@ -0,0 +1,165 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a read only stream that pumps data from a PHP callable.
+ *
+ * When invoking the provided callable, the PumpStream will pass the amount of
+ * data requested to read to the callable. The callable can choose to ignore
+ * this value and return fewer or more bytes than requested. Any extra data
+ * returned by the provided callable is buffered internally until drained using
+ * the read() function of the PumpStream. The provided callable MUST return
+ * false when there is no more data to read.
+ */
+class PumpStream implements StreamInterface
+{
+ /** @var callable */
+ private $source;
+
+ /** @var int */
+ private $size;
+
+ /** @var int */
+ private $tellPos = 0;
+
+ /** @var array */
+ private $metadata;
+
+ /** @var BufferStream */
+ private $buffer;
+
+ /**
+ * @param callable $source Source of the stream data. The callable MAY
+ * accept an integer argument used to control the
+ * amount of data to return. The callable MUST
+ * return a string when called, or false on error
+ * or EOF.
+ * @param array $options Stream options:
+ * - metadata: Hash of metadata to use with stream.
+ * - size: Size of the stream, if known.
+ */
+ public function __construct($source, array $options = array())
+ {
+ $this->source = $source;
+ $this->size = isset($options['size']) ? $options['size'] : null;
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : array();
+ $this->buffer = new BufferStream();
+ }
+
+ public function __toString()
+ {
+ try {
+ return copy_to_string($this);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->tellPos = false;
+ $this->source = null;
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ return $this->tellPos;
+ }
+
+ public function eof()
+ {
+ return !$this->source;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a PumpStream');
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to a PumpStream');
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function read($length)
+ {
+ $data = $this->buffer->read($length);
+ $readLen = strlen($data);
+ $this->tellPos += $readLen;
+ $remaining = $length - $readLen;
+
+ if ($remaining) {
+ $this->pump($remaining);
+ $data .= $this->buffer->read($remaining);
+ $this->tellPos += strlen($data) - $readLen;
+ }
+
+ return $data;
+ }
+
+ public function getContents()
+ {
+ $result = '';
+ while (!$this->eof()) {
+ $result .= $this->read(1000000);
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!$key) {
+ return $this->metadata;
+ }
+
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
+ }
+
+ private function pump($length)
+ {
+ if ($this->source) {
+ do {
+ $data = call_user_func($this->source, $length);
+ if ($data === false || $data === null) {
+ $this->source = null;
+ return;
+ }
+ $this->buffer->write($data);
+ $length -= strlen($data);
+ } while ($length > 0);
+ }
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/Request.php b/vendor/ringcentral/psr7/src/Request.php
new file mode 100644
index 0000000..bb0f2fc
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/Request.php
@@ -0,0 +1,146 @@
+<?php
+namespace RingCentral\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * PSR-7 request implementation.
+ */
+class Request extends MessageTrait implements RequestInterface
+{
+
+ /** @var string */
+ private $method;
+
+ /** @var null|string */
+ private $requestTarget;
+
+ /** @var null|UriInterface */
+ private $uri;
+
+ /**
+ * @param null|string $method HTTP method for the request.
+ * @param null|string|UriInterface $uri URI for the request.
+ * @param array $headers Headers for the message.
+ * @param string|resource|StreamInterface $body Message body.
+ * @param string $protocolVersion HTTP protocol version.
+ *
+ * @throws InvalidArgumentException for an invalid URI
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = array(),
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ if (is_string($uri)) {
+ $uri = new Uri($uri);
+ } elseif (!($uri instanceof UriInterface)) {
+ throw new \InvalidArgumentException(
+ 'URI must be a string or Psr\Http\Message\UriInterface'
+ );
+ }
+
+ $this->method = strtoupper($method);
+ $this->uri = $uri;
+ $this->setHeaders($headers);
+ $this->protocol = $protocolVersion;
+
+ $host = $uri->getHost();
+ if ($host && !$this->hasHeader('Host')) {
+ $this->updateHostFromUri($host);
+ }
+
+ if ($body) {
+ $this->stream = stream_for($body);
+ }
+ }
+
+ public function getRequestTarget()
+ {
+ if ($this->requestTarget !== null) {
+ return $this->requestTarget;
+ }
+
+ $target = $this->uri->getPath();
+ if ($target == null) {
+ $target = '/';
+ }
+ if ($this->uri->getQuery()) {
+ $target .= '?' . $this->uri->getQuery();
+ }
+
+ return $target;
+ }
+
+ public function withRequestTarget($requestTarget)
+ {
+ if (preg_match('#\s#', $requestTarget)) {
+ throw new InvalidArgumentException(
+ 'Invalid request target provided; cannot contain whitespace'
+ );
+ }
+
+ $new = clone $this;
+ $new->requestTarget = $requestTarget;
+ return $new;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function withMethod($method)
+ {
+ $new = clone $this;
+ $new->method = strtoupper($method);
+ return $new;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ if ($uri === $this->uri) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->uri = $uri;
+
+ if (!$preserveHost) {
+ if ($host = $uri->getHost()) {
+ $new->updateHostFromUri($host);
+ }
+ }
+
+ return $new;
+ }
+
+ public function withHeader($header, $value)
+ {
+ /** @var Request $newInstance */
+ $newInstance = parent::withHeader($header, $value);
+ return $newInstance;
+ }
+
+ private function updateHostFromUri($host)
+ {
+ // Ensure Host is the first header.
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
+ if ($port = $this->uri->getPort()) {
+ $host .= ':' . $port;
+ }
+
+ $this->headerLines = array('Host' => array($host)) + $this->headerLines;
+ $this->headers = array('host' => array($host)) + $this->headers;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/Response.php b/vendor/ringcentral/psr7/src/Response.php
new file mode 100644
index 0000000..a6d9451
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/Response.php
@@ -0,0 +1,129 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * PSR-7 response implementation.
+ */
+class Response extends MessageTrait implements ResponseInterface
+{
+
+ /** @var array Map of standard HTTP status code/reason phrases */
+ private static $phrases = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-status',
+ 208 => 'Already Reported',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Time-out',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested range not satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Unordered Collection',
+ 426 => 'Upgrade Required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Time-out',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 511 => 'Network Authentication Required',
+ );
+
+ /** @var null|string */
+ private $reasonPhrase = '';
+
+ /** @var int */
+ private $statusCode = 200;
+
+ /**
+ * @param int $status Status code for the response, if any.
+ * @param array $headers Headers for the response, if any.
+ * @param mixed $body Stream body.
+ * @param string $version Protocol version.
+ * @param string $reason Reason phrase (a default will be used if possible).
+ */
+ public function __construct(
+ $status = 200,
+ array $headers = array(),
+ $body = null,
+ $version = '1.1',
+ $reason = null
+ ) {
+ $this->statusCode = (int) $status;
+
+ if ($body !== null) {
+ $this->stream = stream_for($body);
+ }
+
+ $this->setHeaders($headers);
+ if (!$reason && isset(self::$phrases[$this->statusCode])) {
+ $this->reasonPhrase = self::$phrases[$status];
+ } else {
+ $this->reasonPhrase = (string) $reason;
+ }
+
+ $this->protocol = $version;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $new = clone $this;
+ $new->statusCode = (int) $code;
+ if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) {
+ $reasonPhrase = self::$phrases[$new->statusCode];
+ }
+ $new->reasonPhrase = $reasonPhrase;
+ return $new;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/ServerRequest.php b/vendor/ringcentral/psr7/src/ServerRequest.php
new file mode 100644
index 0000000..8408a09
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/ServerRequest.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\ServerRequestInterface;
+use RingCentral\Psr7\Request;
+
+/**
+ * PSR-7 server-side request implementation.
+ */
+class ServerRequest extends Request implements ServerRequestInterface
+{
+ private $attributes = array();
+
+ private $serverParams = array();
+ private $fileParams = array();
+ private $cookies = array();
+ private $queryParams = array();
+ private $parsedBody = null;
+
+ /**
+ * @param null|string $method HTTP method for the request.
+ * @param null|string|UriInterface $uri URI for the request.
+ * @param array $headers Headers for the message.
+ * @param string|resource|StreamInterface $body Message body.
+ * @param string $protocolVersion HTTP protocol version.
+ * @param array $serverParams Server params of the request.
+ *
+ * @throws InvalidArgumentException for an invalid URI
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = array(),
+ $body = null,
+ $protocolVersion = '1.1',
+ $serverParams = array()
+ ) {
+ parent::__construct($method, $uri, $headers, $body, $protocolVersion);
+ $this->serverParams = $serverParams;
+ }
+
+ public function getServerParams()
+ {
+ return $this->serverParams;
+ }
+
+ public function getCookieParams()
+ {
+ return $this->cookies;
+ }
+
+ public function withCookieParams(array $cookies)
+ {
+ $new = clone $this;
+ $new->cookies = $cookies;
+ return $new;
+ }
+
+ public function getQueryParams()
+ {
+ return $this->queryParams;
+ }
+
+ public function withQueryParams(array $query)
+ {
+ $new = clone $this;
+ $new->queryParams = $query;
+ return $new;
+ }
+
+ public function getUploadedFiles()
+ {
+ return $this->fileParams;
+ }
+
+ public function withUploadedFiles(array $uploadedFiles)
+ {
+ $new = clone $this;
+ $new->fileParams = $uploadedFiles;
+ return $new;
+ }
+
+ public function getParsedBody()
+ {
+ return $this->parsedBody;
+ }
+
+ public function withParsedBody($data)
+ {
+ $new = clone $this;
+ $new->parsedBody = $data;
+ return $new;
+ }
+
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function getAttribute($name, $default = null)
+ {
+ if (!array_key_exists($name, $this->attributes)) {
+ return $default;
+ }
+ return $this->attributes[$name];
+ }
+
+ public function withAttribute($name, $value)
+ {
+ $new = clone $this;
+ $new->attributes[$name] = $value;
+ return $new;
+ }
+
+ public function withoutAttribute($name)
+ {
+ $new = clone $this;
+ unset($new->attributes[$name]);
+ return $new;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/Stream.php b/vendor/ringcentral/psr7/src/Stream.php
new file mode 100644
index 0000000..0a0157c
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/Stream.php
@@ -0,0 +1,245 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * PHP stream implementation.
+ *
+ * @var $stream
+ */
+class Stream implements StreamInterface
+{
+ private $stream;
+ private $size;
+ private $seekable;
+ private $readable;
+ private $writable;
+ private $uri;
+ private $customMetadata;
+
+ /** @var array Hash of readable and writable stream types */
+ private static $readWriteHash = array(
+ 'read' => array(
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
+ 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
+ 'x+t' => true, 'c+t' => true, 'a+' => true
+ ),
+ 'write' => array(
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
+ 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
+ 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
+ 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
+ )
+ );
+
+ /**
+ * This constructor accepts an associative array of options.
+ *
+ * - size: (int) If a read stream would otherwise have an indeterminate
+ * size, but the size is known due to foreknownledge, then you can
+ * provide that size, in bytes.
+ * - metadata: (array) Any additional metadata to return when the metadata
+ * of the stream is accessed.
+ *
+ * @param resource $stream Stream resource to wrap.
+ * @param array $options Associative array of options.
+ *
+ * @throws \InvalidArgumentException if the stream is not a stream resource
+ */
+ public function __construct($stream, $options = array())
+ {
+ if (!is_resource($stream)) {
+ throw new \InvalidArgumentException('Stream must be a resource');
+ }
+
+ if (isset($options['size'])) {
+ $this->size = $options['size'];
+ }
+
+ $this->customMetadata = isset($options['metadata'])
+ ? $options['metadata']
+ : array();
+
+ $this->stream = $stream;
+ $meta = stream_get_meta_data($this->stream);
+ $this->seekable = $meta['seekable'];
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
+ $this->uri = $this->getMetadata('uri');
+ }
+
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ throw new \RuntimeException('The stream is detached');
+ }
+
+ throw new \BadMethodCallException('No value for ' . $name);
+ }
+
+ /**
+ * Closes the stream when the destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->seek(0);
+ return (string) stream_get_contents($this->stream);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ $contents = stream_get_contents($this->stream);
+
+ if ($contents === false) {
+ throw new \RuntimeException('Unable to read stream contents');
+ }
+
+ return $contents;
+ }
+
+ public function close()
+ {
+ if (isset($this->stream)) {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->detach();
+ }
+ }
+
+ public function detach()
+ {
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ $result = $this->stream;
+ unset($this->stream);
+ $this->size = $this->uri = null;
+ $this->readable = $this->writable = $this->seekable = false;
+
+ return $result;
+ }
+
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ // Clear the stat cache if the stream has a URI
+ if ($this->uri) {
+ clearstatcache(true, $this->uri);
+ }
+
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ }
+
+ return null;
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function eof()
+ {
+ return !$this->stream || feof($this->stream);
+ }
+
+ public function tell()
+ {
+ $result = ftell($this->stream);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to determine stream position');
+ }
+
+ return $result;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('Stream is not seekable');
+ } elseif (fseek($this->stream, $offset, $whence) === -1) {
+ throw new \RuntimeException('Unable to seek to stream position '
+ . $offset . ' with whence ' . var_export($whence, true));
+ }
+ }
+
+ public function read($length)
+ {
+ if (!$this->readable) {
+ throw new \RuntimeException('Cannot read from non-readable stream');
+ }
+
+ return fread($this->stream, $length);
+ }
+
+ public function write($string)
+ {
+ if (!$this->writable) {
+ throw new \RuntimeException('Cannot write to a non-writable stream');
+ }
+
+ // We can't know the size after writing anything
+ $this->size = null;
+ $result = fwrite($this->stream, $string);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to write to stream');
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!isset($this->stream)) {
+ return $key ? null : array();
+ } elseif (!$key) {
+ return $this->customMetadata + stream_get_meta_data($this->stream);
+ } elseif (isset($this->customMetadata[$key])) {
+ return $this->customMetadata[$key];
+ }
+
+ $meta = stream_get_meta_data($this->stream);
+
+ return isset($meta[$key]) ? $meta[$key] : null;
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/StreamDecoratorTrait.php b/vendor/ringcentral/psr7/src/StreamDecoratorTrait.php
new file mode 100644
index 0000000..e22c674
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/StreamDecoratorTrait.php
@@ -0,0 +1,139 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator trait
+ * @property StreamInterface stream
+ */
+abstract class StreamDecoratorTrait implements StreamInterface
+{
+ /**
+ * @param StreamInterface $stream Stream to decorate
+ */
+ public function __construct(StreamInterface $stream = null)
+ {
+ if ($stream) $this->stream = $stream;
+ }
+
+ /**
+ * Magic method used to create a new stream if streams are not added in
+ * the constructor of a decorator (e.g., LazyOpenStream).
+ *
+ * @param string $name Name of the property (allows "stream" only).
+ *
+ * @return StreamInterface
+ */
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ $this->stream = $this->createStream();
+ return $this->stream;
+ }
+
+ throw new \UnexpectedValueException("$name not found on class");
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
+ trigger_error('StreamDecorator::__toString exception: '
+ . (string) $e, E_USER_ERROR);
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ $result = call_user_func_array(array($this->stream, $method), $args);
+
+ // Always return the wrapped object if the result is a return $this
+ return $result === $this->stream ? $this : $result;
+ }
+
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+}
diff --git a/vendor/ringcentral/psr7/src/StreamWrapper.php b/vendor/ringcentral/psr7/src/StreamWrapper.php
new file mode 100644
index 0000000..8cc07d7
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/StreamWrapper.php
@@ -0,0 +1,121 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Converts Guzzle streams into PHP stream resources.
+ */
+class StreamWrapper
+{
+ /** @var resource */
+ public $context;
+
+ /** @var StreamInterface */
+ private $stream;
+
+ /** @var string r, r+, or w */
+ private $mode;
+
+ /**
+ * Returns a resource representing the stream.
+ *
+ * @param StreamInterface $stream The stream to get a resource for
+ *
+ * @return resource
+ * @throws \InvalidArgumentException if stream is not readable or writable
+ */
+ public static function getResource(StreamInterface $stream)
+ {
+ self::register();
+
+ if ($stream->isReadable()) {
+ $mode = $stream->isWritable() ? 'r+' : 'r';
+ } elseif ($stream->isWritable()) {
+ $mode = 'w';
+ } else {
+ throw new \InvalidArgumentException('The stream must be readable, '
+ . 'writable, or both.');
+ }
+
+ return fopen('guzzle://stream', $mode, null, stream_context_create(array(
+ 'guzzle' => array('stream' => $stream)
+ )));
+ }
+
+ /**
+ * Registers the stream wrapper if needed
+ */
+ public static function register()
+ {
+ if (!in_array('guzzle', stream_get_wrappers())) {
+ stream_wrapper_register('guzzle', __CLASS__);
+ }
+ }
+
+ public function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $options = stream_context_get_options($this->context);
+
+ if (!isset($options['guzzle']['stream'])) {
+ return false;
+ }
+
+ $this->mode = $mode;
+ $this->stream = $options['guzzle']['stream'];
+
+ return true;
+ }
+
+ public function stream_read($count)
+ {
+ return $this->stream->read($count);
+ }
+
+ public function stream_write($data)
+ {
+ return (int) $this->stream->write($data);
+ }
+
+ public function stream_tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function stream_eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ $this->stream->seek($offset, $whence);
+
+ return true;
+ }
+
+ public function stream_stat()
+ {
+ static $modeMap = array(
+ 'r' => 33060,
+ 'r+' => 33206,
+ 'w' => 33188
+ );
+
+ return array(
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => $modeMap[$this->mode],
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => $this->stream->getSize() ?: 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ );
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/Uri.php b/vendor/ringcentral/psr7/src/Uri.php
new file mode 100644
index 0000000..5323cdc
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/Uri.php
@@ -0,0 +1,601 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Basic PSR-7 URI implementation.
+ *
+ * @link https://github.com/phly/http This class is based upon
+ * Matthew Weier O'Phinney's URI implementation in phly/http.
+ */
+class Uri implements UriInterface
+{
+ private static $schemes = array(
+ 'http' => 80,
+ 'https' => 443,
+ );
+
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
+ private static $replaceQuery = array('=' => '%3D', '&' => '%26');
+
+ /** @var string Uri scheme. */
+ private $scheme = '';
+
+ /** @var string Uri user info. */
+ private $userInfo = '';
+
+ /** @var string Uri host. */
+ private $host = '';
+
+ /** @var int|null Uri port. */
+ private $port;
+
+ /** @var string Uri path. */
+ private $path = '';
+
+ /** @var string Uri query string. */
+ private $query = '';
+
+ /** @var string Uri fragment. */
+ private $fragment = '';
+
+ /**
+ * @param string $uri URI to parse and wrap.
+ */
+ public function __construct($uri = '')
+ {
+ if ($uri != null) {
+ $parts = parse_url($uri);
+ if ($parts === false) {
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ }
+ $this->applyParts($parts);
+ }
+ }
+
+ public function __toString()
+ {
+ return self::createUriString(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->getPath(),
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+ public static function removeDotSegments($path)
+ {
+ static $noopPaths = array('' => true, '/' => true, '*' => true);
+ static $ignoreSegments = array('.' => true, '..' => true);
+
+ if (isset($noopPaths[$path])) {
+ return $path;
+ }
+
+ $results = array();
+ $segments = explode('/', $path);
+ foreach ($segments as $segment) {
+ if ($segment == '..') {
+ array_pop($results);
+ } elseif (!isset($ignoreSegments[$segment])) {
+ $results[] = $segment;
+ }
+ }
+
+ $newPath = implode('/', $results);
+ // Add the leading slash if necessary
+ if (substr($path, 0, 1) === '/' &&
+ substr($newPath, 0, 1) !== '/'
+ ) {
+ $newPath = '/' . $newPath;
+ }
+
+ // Add the trailing slash if necessary
+ if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
+ $newPath .= '/';
+ }
+
+ return $newPath;
+ }
+
+ /**
+ * Resolve a base URI with a relative URI and return a new URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param string $rel Relative URI
+ *
+ * @return UriInterface
+ */
+ public static function resolve(UriInterface $base, $rel)
+ {
+ if ($rel === null || $rel === '') {
+ return $base;
+ }
+
+ if (!($rel instanceof UriInterface)) {
+ $rel = new self($rel);
+ }
+
+ // Return the relative uri as-is if it has a scheme.
+ if ($rel->getScheme()) {
+ return $rel->withPath(static::removeDotSegments($rel->getPath()));
+ }
+
+ $relParts = array(
+ 'scheme' => $rel->getScheme(),
+ 'authority' => $rel->getAuthority(),
+ 'path' => $rel->getPath(),
+ 'query' => $rel->getQuery(),
+ 'fragment' => $rel->getFragment()
+ );
+
+ $parts = array(
+ 'scheme' => $base->getScheme(),
+ 'authority' => $base->getAuthority(),
+ 'path' => $base->getPath(),
+ 'query' => $base->getQuery(),
+ 'fragment' => $base->getFragment()
+ );
+
+ if (!empty($relParts['authority'])) {
+ $parts['authority'] = $relParts['authority'];
+ $parts['path'] = self::removeDotSegments($relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ } elseif (!empty($relParts['path'])) {
+ if (substr($relParts['path'], 0, 1) == '/') {
+ $parts['path'] = self::removeDotSegments($relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ } else {
+ if (!empty($parts['authority']) && empty($parts['path'])) {
+ $mergedPath = '/';
+ } else {
+ $mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1);
+ }
+ $parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ }
+ } elseif (!empty($relParts['query'])) {
+ $parts['query'] = $relParts['query'];
+ } elseif ($relParts['fragment'] != null) {
+ $parts['fragment'] = $relParts['fragment'];
+ }
+
+ return new self(static::createUriString(
+ $parts['scheme'],
+ $parts['authority'],
+ $parts['path'],
+ $parts['query'],
+ $parts['fragment']
+ ));
+ }
+
+ /**
+ * Create a new URI with a specific query string value removed.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed.
+ *
+ * Note: this function will convert "=" to "%3D" and "&" to "%26".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Query string key value pair to remove.
+ *
+ * @return UriInterface
+ */
+ public static function withoutQueryValue(UriInterface $uri, $key)
+ {
+ $current = $uri->getQuery();
+ if (!$current) {
+ return $uri;
+ }
+
+ $result = array();
+ foreach (explode('&', $current) as $part) {
+ $subParts = explode('=', $part);
+ if ($subParts[0] !== $key) {
+ $result[] = $part;
+ };
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Create a new URI with a specific query string value.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed and replaced with the given key value pair.
+ *
+ * Note: this function will convert "=" to "%3D" and "&" to "%26".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Key to set.
+ * @param string $value Value to set.
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValue(UriInterface $uri, $key, $value)
+ {
+ $current = $uri->getQuery();
+ $key = strtr($key, self::$replaceQuery);
+
+ if (!$current) {
+ $result = array();
+ } else {
+ $result = array();
+ foreach (explode('&', $current) as $part) {
+ $subParts = explode('=', $part);
+ if ($subParts[0] !== $key) {
+ $result[] = $part;
+ };
+ }
+ }
+
+ if ($value !== null) {
+ $result[] = $key . '=' . strtr($value, self::$replaceQuery);
+ } else {
+ $result[] = $key;
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Create a URI from a hash of parse_url parts.
+ *
+ * @param array $parts
+ *
+ * @return self
+ */
+ public static function fromParts(array $parts)
+ {
+ $uri = new self();
+ $uri->applyParts($parts);
+ return $uri;
+ }
+
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ public function getAuthority()
+ {
+ if (empty($this->host)) {
+ return '';
+ }
+
+ $authority = $this->host;
+ if (!empty($this->userInfo)) {
+ $authority = $this->userInfo . '@' . $authority;
+ }
+
+ if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
+ $authority .= ':' . $this->port;
+ }
+
+ return $authority;
+ }
+
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function getPath()
+ {
+ return $this->path == null ? '' : $this->path;
+ }
+
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ public function withScheme($scheme)
+ {
+ $scheme = $this->filterScheme($scheme);
+
+ if ($this->scheme === $scheme) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->scheme = $scheme;
+ $new->port = $new->filterPort($new->scheme, $new->host, $new->port);
+ return $new;
+ }
+
+ public function withUserInfo($user, $password = null)
+ {
+ $info = $user;
+ if ($password) {
+ $info .= ':' . $password;
+ }
+
+ if ($this->userInfo === $info) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->userInfo = $info;
+ return $new;
+ }
+
+ public function withHost($host)
+ {
+ if ($this->host === $host) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->host = $host;
+ return $new;
+ }
+
+ public function withPort($port)
+ {
+ $port = $this->filterPort($this->scheme, $this->host, $port);
+
+ if ($this->port === $port) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->port = $port;
+ return $new;
+ }
+
+ public function withPath($path)
+ {
+ if (!is_string($path)) {
+ throw new \InvalidArgumentException(
+ 'Invalid path provided; must be a string'
+ );
+ }
+
+ $path = $this->filterPath($path);
+
+ if ($this->path === $path) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->path = $path;
+ return $new;
+ }
+
+ public function withQuery($query)
+ {
+ if (!is_string($query) && !method_exists($query, '__toString')) {
+ throw new \InvalidArgumentException(
+ 'Query string must be a string'
+ );
+ }
+
+ $query = (string) $query;
+ if (substr($query, 0, 1) === '?') {
+ $query = substr($query, 1);
+ }
+
+ $query = $this->filterQueryAndFragment($query);
+
+ if ($this->query === $query) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->query = $query;
+ return $new;
+ }
+
+ public function withFragment($fragment)
+ {
+ if (substr($fragment, 0, 1) === '#') {
+ $fragment = substr($fragment, 1);
+ }
+
+ $fragment = $this->filterQueryAndFragment($fragment);
+
+ if ($this->fragment === $fragment) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->fragment = $fragment;
+ return $new;
+ }
+
+ /**
+ * Apply parse_url parts to a URI.
+ *
+ * @param $parts Array of parse_url parts to apply.
+ */
+ private function applyParts(array $parts)
+ {
+ $this->scheme = isset($parts['scheme'])
+ ? $this->filterScheme($parts['scheme'])
+ : '';
+ $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
+ $this->host = isset($parts['host']) ? $parts['host'] : '';
+ $this->port = !empty($parts['port'])
+ ? $this->filterPort($this->scheme, $this->host, $parts['port'])
+ : null;
+ $this->path = isset($parts['path'])
+ ? $this->filterPath($parts['path'])
+ : '';
+ $this->query = isset($parts['query'])
+ ? $this->filterQueryAndFragment($parts['query'])
+ : '';
+ $this->fragment = isset($parts['fragment'])
+ ? $this->filterQueryAndFragment($parts['fragment'])
+ : '';
+ if (isset($parts['pass'])) {
+ $this->userInfo .= ':' . $parts['pass'];
+ }
+ }
+
+ /**
+ * Create a URI string from its various parts
+ *
+ * @param string $scheme
+ * @param string $authority
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ * @return string
+ */
+ private static function createUriString($scheme, $authority, $path, $query, $fragment)
+ {
+ $uri = '';
+
+ if (!empty($scheme)) {
+ $uri .= $scheme . '://';
+ }
+
+ if (!empty($authority)) {
+ $uri .= $authority;
+ }
+
+ if ($path != null) {
+ // Add a leading slash if necessary.
+ if ($uri && substr($path, 0, 1) !== '/') {
+ $uri .= '/';
+ }
+ $uri .= $path;
+ }
+
+ if ($query != null) {
+ $uri .= '?' . $query;
+ }
+
+ if ($fragment != null) {
+ $uri .= '#' . $fragment;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Is a given port non-standard for the current scheme?
+ *
+ * @param string $scheme
+ * @param string $host
+ * @param int $port
+ * @return bool
+ */
+ private static function isNonStandardPort($scheme, $host, $port)
+ {
+ if (!$scheme && $port) {
+ return true;
+ }
+
+ if (!$host || !$port) {
+ return false;
+ }
+
+ return !isset(static::$schemes[$scheme]) || $port !== static::$schemes[$scheme];
+ }
+
+ /**
+ * @param string $scheme
+ *
+ * @return string
+ */
+ private function filterScheme($scheme)
+ {
+ $scheme = strtolower($scheme);
+ $scheme = rtrim($scheme, ':/');
+
+ return $scheme;
+ }
+
+ /**
+ * @param string $scheme
+ * @param string $host
+ * @param int $port
+ *
+ * @return int|null
+ *
+ * @throws \InvalidArgumentException If the port is invalid.
+ */
+ private function filterPort($scheme, $host, $port)
+ {
+ if (null !== $port) {
+ $port = (int) $port;
+ if (1 > $port || 0xffff < $port) {
+ throw new \InvalidArgumentException(
+ sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
+ );
+ }
+ }
+
+ return $this->isNonStandardPort($scheme, $host, $port) ? $port : null;
+ }
+
+ /**
+ * Filters the path of a URI
+ *
+ * @param $path
+ *
+ * @return string
+ */
+ private function filterPath($path)
+ {
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
+ array($this, 'rawurlencodeMatchZero'),
+ $path
+ );
+ }
+
+ /**
+ * Filters the query string or fragment of a URI.
+ *
+ * @param $str
+ *
+ * @return string
+ */
+ private function filterQueryAndFragment($str)
+ {
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
+ array($this, 'rawurlencodeMatchZero'),
+ $str
+ );
+ }
+
+ private function rawurlencodeMatchZero(array $match)
+ {
+ return rawurlencode($match[0]);
+ }
+}
diff --git a/vendor/ringcentral/psr7/src/functions.php b/vendor/ringcentral/psr7/src/functions.php
new file mode 100644
index 0000000..3c4c549
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/functions.php
@@ -0,0 +1,835 @@
+<?php
+namespace RingCentral\Psr7;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+// Manually define missing constants for PHP 5.3
+defined('PHP_QUERY_RFC1738') or define('PHP_QUERY_RFC1738', 1);
+defined('PHP_QUERY_RFC3986') or define('PHP_QUERY_RFC3986', 2);
+
+/**
+ * Returns the string representation of an HTTP message.
+ *
+ * @param MessageInterface $message Message to convert to a string.
+ *
+ * @return string
+ */
+function str(MessageInterface $message)
+{
+ if ($message instanceof RequestInterface) {
+ $msg = trim($message->getMethod() . ' '
+ . $message->getRequestTarget())
+ . ' HTTP/' . $message->getProtocolVersion();
+ if (!$message->hasHeader('host')) {
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
+ }
+ } elseif ($message instanceof ResponseInterface) {
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
+ . $message->getStatusCode() . ' '
+ . $message->getReasonPhrase();
+ } else {
+ throw new \InvalidArgumentException('Unknown message type');
+ }
+
+ foreach ($message->getHeaders() as $name => $values) {
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
+ }
+
+ return "{$msg}\r\n\r\n" . $message->getBody();
+}
+
+/**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
+ * returns a UriInterface for the given value. If the value is already a
+ * `UriInterface`, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ * @throws \InvalidArgumentException
+ */
+function uri_for($uri)
+{
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ } elseif (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+}
+
+/**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * @param resource|string|StreamInterface $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return Stream
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ */
+function stream_for($resource = '', array $options = array())
+{
+ switch (gettype($resource)) {
+ case 'string':
+ $stream = fopen('php://temp', 'r+');
+ if ($resource !== '') {
+ fwrite($stream, $resource);
+ fseek($stream, 0);
+ }
+ return new Stream($stream, $options);
+ case 'resource':
+ return new Stream($resource, $options);
+ case 'object':
+ if ($resource instanceof StreamInterface) {
+ return $resource;
+ } elseif ($resource instanceof \Iterator) {
+ return new PumpStream(function () use ($resource) {
+ if (!$resource->valid()) {
+ return false;
+ }
+ $result = $resource->current();
+ $resource->next();
+ return $result;
+ }, $options);
+ } elseif (method_exists($resource, '__toString')) {
+ return stream_for((string) $resource, $options);
+ }
+ break;
+ case 'NULL':
+ return new Stream(fopen('php://temp', 'r+'), $options);
+ }
+
+ if (is_callable($resource)) {
+ return new PumpStream($resource, $options);
+ }
+
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
+}
+
+/**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair
+ * data of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ */
+function parse_header($header)
+{
+ static $trimmed = "\"' \n\t\r";
+ $params = $matches = array();
+
+ foreach (normalize_header($header) as $val) {
+ $part = array();
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ $m = $matches[0];
+ if (isset($m[1])) {
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
+ } else {
+ $part[] = trim($m[0], $trimmed);
+ }
+ }
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+}
+
+/**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ */
+function normalize_header($header)
+{
+ if (!is_array($header)) {
+ return array_map('trim', explode(',', $header));
+ }
+
+ $result = array();
+ foreach ($header as $value) {
+ foreach ((array) $value as $v) {
+ if (strpos($v, ',') === false) {
+ $result[] = $v;
+ continue;
+ }
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
+ $result[] = trim($vv);
+ }
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Clone and modify a request with the given changes.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ */
+function modify_request(RequestInterface $request, array $changes)
+{
+ if (!$changes) {
+ return $request;
+ }
+
+ $headers = $request->getHeaders();
+
+ if (!isset($changes['uri'])) {
+ $uri = $request->getUri();
+ } else {
+ // Remove the host header if one is on the URI
+ if ($host = $changes['uri']->getHost()) {
+ $changes['set_headers']['Host'] = $host;
+ }
+ $uri = $changes['uri'];
+ }
+
+ if (!empty($changes['remove_headers'])) {
+ $headers = _caseless_remove($changes['remove_headers'], $headers);
+ }
+
+ if (!empty($changes['set_headers'])) {
+ $headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
+ $headers = $changes['set_headers'] + $headers;
+ }
+
+ if (isset($changes['query'])) {
+ $uri = $uri->withQuery($changes['query']);
+ }
+
+ return new Request(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion()
+ );
+}
+
+/**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()` returns a
+ * value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ */
+function rewind_body(MessageInterface $message)
+{
+ $body = $message->getBody();
+
+ if ($body->tell()) {
+ $body->rewind();
+ }
+}
+
+/**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ * @throws \RuntimeException if the file cannot be opened
+ */
+function try_fopen($filename, $mode)
+{
+ $ex = null;
+ $fargs = func_get_args();
+ set_error_handler(function () use ($filename, $mode, &$ex, $fargs) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open %s using mode %s: %s',
+ $filename,
+ $mode,
+ $fargs[1]
+ ));
+ });
+
+ $handle = fopen($filename, $mode);
+ restore_error_handler();
+
+ if ($ex) {
+ /** @var $ex \RuntimeException */
+ throw $ex;
+ }
+
+ return $handle;
+}
+
+/**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ * @return string
+ * @throws \RuntimeException on error.
+ */
+function copy_to_string(StreamInterface $stream, $maxLen = -1)
+{
+ $buffer = '';
+
+ if ($maxLen === -1) {
+ while (!$stream->eof()) {
+ $buf = $stream->read(1048576);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ }
+ return $buffer;
+ }
+
+ $len = 0;
+ while (!$stream->eof() && $len < $maxLen) {
+ $buf = $stream->read($maxLen - $len);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ $len = strlen($buffer);
+ }
+
+ return $buffer;
+}
+
+/**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ */
+function copy_to_stream(
+ StreamInterface $source,
+ StreamInterface $dest,
+ $maxLen = -1
+) {
+ if ($maxLen === -1) {
+ while (!$source->eof()) {
+ if (!$dest->write($source->read(1048576))) {
+ break;
+ }
+ }
+ return;
+ }
+
+ $bytes = 0;
+ while (!$source->eof()) {
+ $buf = $source->read($maxLen - $bytes);
+ if (!($len = strlen($buf))) {
+ break;
+ }
+ $bytes += $len;
+ $dest->write($buf);
+ if ($bytes == $maxLen) {
+ break;
+ }
+ }
+}
+
+/**
+ * Calculate a hash of a Stream
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ * @throws \RuntimeException on error.
+ */
+function hash(
+ StreamInterface $stream,
+ $algo,
+ $rawOutput = false
+) {
+ $pos = $stream->tell();
+
+ if ($pos > 0) {
+ $stream->rewind();
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->eof()) {
+ hash_update($ctx, $stream->read(1048576));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+}
+
+/**
+ * Read a line from the stream up to the maximum allowed buffer length
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int $maxLength Maximum buffer length
+ *
+ * @return string|bool
+ */
+function readline(StreamInterface $stream, $maxLength = null)
+{
+ $buffer = '';
+ $size = 0;
+
+ while (!$stream->eof()) {
+ // Using a loose equality here to match on '' and false.
+ if (null == ($byte = $stream->read(1))) {
+ return $buffer;
+ }
+ $buffer .= $byte;
+ // Break when a new line is found or the max length - 1 is reached
+ if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
+ break;
+ }
+ }
+
+ return $buffer;
+}
+
+/**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ */
+function parse_request($message)
+{
+ $data = _parse_message($message);
+ $matches = array();
+ if (!preg_match('/^[a-zA-Z]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
+ throw new \InvalidArgumentException('Invalid request string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+ $subParts = isset($parts[2]) ? explode('/', $parts[2]) : array();
+ $version = isset($parts[2]) ? $subParts[1] : '1.1';
+
+ $request = new Request(
+ $parts[0],
+ $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
+ $data['headers'],
+ $data['body'],
+ $version
+ );
+
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
+}
+
+/**
+ * Parses a request message string into a server request object.
+ *
+ * @param string $message Request message string.
+ * @param array $serverParams Server params that will be added to the
+ * ServerRequest object
+ *
+ * @return ServerRequest
+ */
+function parse_server_request($message, array $serverParams = array())
+{
+ $request = parse_request($message);
+
+ return new ServerRequest(
+ $request->getMethod(),
+ $request->getUri(),
+ $request->getHeaders(),
+ $request->getBody(),
+ $request->getProtocolVersion(),
+ $serverParams
+ );
+}
+
+/**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ */
+function parse_response($message)
+{
+ $data = _parse_message($message);
+ // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
+ // between status-code and reason-phrase is required. But browsers accept
+ // responses without space and reason as well.
+ if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
+ throw new \InvalidArgumentException('Invalid response string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+ $subParts = explode('/', $parts[0]);
+
+ return new Response(
+ $parts[1],
+ $data['headers'],
+ $data['body'],
+ $subParts[1],
+ isset($parts[2]) ? $parts[2] : null
+ );
+}
+
+/**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key
+ * value pair will become an array. This function does not parse nested
+ * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
+ * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
+ *
+ * @param string $str Query string to parse
+ * @param bool|string $urlEncoding How the query string is encoded
+ *
+ * @return array
+ */
+function parse_query($str, $urlEncoding = true)
+{
+ $result = array();
+
+ if ($str === '') {
+ return $result;
+ }
+
+ if ($urlEncoding === true) {
+ $decoder = function ($value) {
+ return rawurldecode(str_replace('+', ' ', $value));
+ };
+ } elseif ($urlEncoding == PHP_QUERY_RFC3986) {
+ $decoder = 'rawurldecode';
+ } elseif ($urlEncoding == PHP_QUERY_RFC1738) {
+ $decoder = 'urldecode';
+ } else {
+ $decoder = function ($str) { return $str; };
+ }
+
+ foreach (explode('&', $str) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ $key = $decoder($parts[0]);
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
+ if (!isset($result[$key])) {
+ $result[$key] = $value;
+ } else {
+ if (!is_array($result[$key])) {
+ $result[$key] = array($result[$key]);
+ }
+ $result[$key][] = $value;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of parseQuery() to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like http_build_query would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ * @return string
+ */
+function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
+{
+ if (!$params) {
+ return '';
+ }
+
+ if ($encoding === false) {
+ $encoder = function ($str) { return $str; };
+ } elseif ($encoding == PHP_QUERY_RFC3986) {
+ $encoder = 'rawurlencode';
+ } elseif ($encoding == PHP_QUERY_RFC1738) {
+ $encoder = 'urlencode';
+ } else {
+ throw new \InvalidArgumentException('Invalid type');
+ }
+
+ $qs = '';
+ foreach ($params as $k => $v) {
+ $k = $encoder($k);
+ if (!is_array($v)) {
+ $qs .= $k;
+ if ($v !== null) {
+ $qs .= '=' . $encoder($v);
+ }
+ $qs .= '&';
+ } else {
+ foreach ($v as $vv) {
+ $qs .= $k;
+ if ($vv !== null) {
+ $qs .= '=' . $encoder($vv);
+ }
+ $qs .= '&';
+ }
+ }
+ }
+
+ return $qs ? (string) substr($qs, 0, -1) : '';
+}
+
+/**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param $filename
+ *
+ * @return null|string
+ */
+function mimetype_from_filename($filename)
+{
+ return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
+}
+
+/**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param $extension string The file extension.
+ *
+ * @return string|null
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ */
+function mimetype_from_extension($extension)
+{
+ static $mimetypes = array(
+ '7z' => 'application/x-7z-compressed',
+ 'aac' => 'audio/x-aac',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'atom' => 'application/atom+xml',
+ 'avi' => 'video/x-msvideo',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'cer' => 'application/pkix-cert',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'css' => 'text/css',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'deb' => 'application/x-debian-package',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dvi' => 'application/x-dvi',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'etx' => 'text/x-setext',
+ 'flac' => 'audio/flac',
+ 'flv' => 'video/x-flv',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ini' => 'text/plain',
+ 'iso' => 'application/x-iso9660-image',
+ 'jar' => 'application/java-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'latex' => 'application/x-latex',
+ 'log' => 'text/plain',
+ 'm4a' => 'audio/mp4',
+ 'm4v' => 'video/mp4',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pdf' => 'application/pdf',
+ 'pgm' => 'image/x-portable-graymap',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'svg' => 'image/svg+xml',
+ 'swf' => 'application/x-shockwave-flash',
+ 'tar' => 'application/x-tar',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'torrent' => 'application/x-bittorrent',
+ 'ttf' => 'application/x-font-ttf',
+ 'txt' => 'text/plain',
+ 'wav' => 'audio/x-wav',
+ 'webm' => 'video/webm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'video/x-ms-wmv',
+ 'woff' => 'application/x-font-woff',
+ 'wsdl' => 'application/wsdl+xml',
+ 'xbm' => 'image/x-xbitmap',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'yaml' => 'text/yaml',
+ 'yml' => 'text/yaml',
+ 'zip' => 'application/zip',
+ );
+
+ $extension = strtolower($extension);
+
+ return isset($mimetypes[$extension])
+ ? $mimetypes[$extension]
+ : null;
+}
+
+/**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ * @internal
+ */
+function _parse_message($message)
+{
+ if (!$message) {
+ throw new \InvalidArgumentException('Invalid message');
+ }
+
+ // Iterate over each line in the message, accounting for line endings
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $result = array('start-line' => array_shift($lines), 'headers' => array(), 'body' => '');
+ array_shift($lines);
+
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
+ $line = $lines[$i];
+ // If two line breaks were encountered, then this is the end of body
+ if (empty($line)) {
+ if ($i < $totalLines - 1) {
+ $result['body'] = implode('', array_slice($lines, $i + 2));
+ }
+ break;
+ }
+ if (strpos($line, ':')) {
+ $parts = explode(':', $line, 2);
+ $key = trim($parts[0]);
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
+ $result['headers'][$key][] = $value;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ * @internal
+ */
+function _parse_request_uri($path, array $headers)
+{
+ $hostKey = array_filter(array_keys($headers), function ($k) {
+ return strtolower($k) === 'host';
+ });
+
+ // If no host is found, then a full URI cannot be constructed.
+ if (!$hostKey) {
+ return $path;
+ }
+
+ $host = $headers[reset($hostKey)][0];
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
+
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
+}
+
+/** @internal */
+function _caseless_remove($keys, array $data)
+{
+ $result = array();
+
+ foreach ($keys as &$key) {
+ $key = strtolower($key);
+ }
+
+ foreach ($data as $k => $v) {
+ if (!in_array(strtolower($k), $keys)) {
+ $result[$k] = $v;
+ }
+ }
+
+ return $result;
+}
diff --git a/vendor/ringcentral/psr7/src/functions_include.php b/vendor/ringcentral/psr7/src/functions_include.php
new file mode 100644
index 0000000..252e0cf
--- /dev/null
+++ b/vendor/ringcentral/psr7/src/functions_include.php
@@ -0,0 +1,6 @@
+<?php
+
+// Don't redefine the functions if included multiple times.
+if (!function_exists('RingCentral\Psr7\str')) {
+ require __DIR__ . '/functions.php';
+}
diff --git a/vendor/symfony/polyfill-ctype/Ctype.php b/vendor/symfony/polyfill-ctype/Ctype.php
new file mode 100644
index 0000000..ba75a2c
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/Ctype.php
@@ -0,0 +1,232 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Ctype;
+
+/**
+ * Ctype implementation through regex.
+ *
+ * @internal
+ *
+ * @author Gert de Pagter <BackEndTea@gmail.com>
+ */
+final class Ctype
+{
+ /**
+ * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-alnum
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_alnum($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a letter, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-alpha
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_alpha($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-cntrl
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_cntrl($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-digit
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_digit($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
+ *
+ * @see https://php.net/ctype-graph
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_graph($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a lowercase letter.
+ *
+ * @see https://php.net/ctype-lower
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_lower($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
+ *
+ * @see https://php.net/ctype-print
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_print($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-punct
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_punct($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
+ *
+ * @see https://php.net/ctype-space
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_space($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is an uppercase letter.
+ *
+ * @see https://php.net/ctype-upper
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_upper($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
+ *
+ * @see https://php.net/ctype-xdigit
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_xdigit($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
+ }
+
+ /**
+ * Converts integers to their char versions according to normal ctype behaviour, if needed.
+ *
+ * If an integer between -128 and 255 inclusive is provided,
+ * it is interpreted as the ASCII value of a single character
+ * (negative values have 256 added in order to allow characters in the Extended ASCII range).
+ * Any other integer is interpreted as a string containing the decimal digits of the integer.
+ *
+ * @param mixed $int
+ * @param string $function
+ *
+ * @return mixed
+ */
+ private static function convert_int_to_char_for_ctype($int, $function)
+ {
+ if (!\is_int($int)) {
+ return $int;
+ }
+
+ if ($int < -128 || $int > 255) {
+ return (string) $int;
+ }
+
+ if (\PHP_VERSION_ID >= 80100) {
+ @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
+ }
+
+ if ($int < 0) {
+ $int += 256;
+ }
+
+ return \chr($int);
+ }
+}
diff --git a/vendor/symfony/polyfill-ctype/LICENSE b/vendor/symfony/polyfill-ctype/LICENSE
new file mode 100644
index 0000000..3f853aa
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-2019 Fabien Potencier
+
+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/symfony/polyfill-ctype/bootstrap.php b/vendor/symfony/polyfill-ctype/bootstrap.php
new file mode 100644
index 0000000..d54524b
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/bootstrap.php
@@ -0,0 +1,50 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Ctype as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!function_exists('ctype_alnum')) {
+ function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
+}
+if (!function_exists('ctype_alpha')) {
+ function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
+}
+if (!function_exists('ctype_cntrl')) {
+ function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
+}
+if (!function_exists('ctype_digit')) {
+ function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
+}
+if (!function_exists('ctype_graph')) {
+ function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
+}
+if (!function_exists('ctype_lower')) {
+ function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
+}
+if (!function_exists('ctype_print')) {
+ function ctype_print($text) { return p\Ctype::ctype_print($text); }
+}
+if (!function_exists('ctype_punct')) {
+ function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
+}
+if (!function_exists('ctype_space')) {
+ function ctype_space($text) { return p\Ctype::ctype_space($text); }
+}
+if (!function_exists('ctype_upper')) {
+ function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
+}
+if (!function_exists('ctype_xdigit')) {
+ function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
+}
diff --git a/vendor/symfony/polyfill-ctype/bootstrap80.php b/vendor/symfony/polyfill-ctype/bootstrap80.php
new file mode 100644
index 0000000..ab2f861
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/bootstrap80.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Ctype as p;
+
+if (!function_exists('ctype_alnum')) {
+ function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
+}
+if (!function_exists('ctype_alpha')) {
+ function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
+}
+if (!function_exists('ctype_cntrl')) {
+ function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
+}
+if (!function_exists('ctype_digit')) {
+ function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
+}
+if (!function_exists('ctype_graph')) {
+ function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
+}
+if (!function_exists('ctype_lower')) {
+ function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
+}
+if (!function_exists('ctype_print')) {
+ function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
+}
+if (!function_exists('ctype_punct')) {
+ function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
+}
+if (!function_exists('ctype_space')) {
+ function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
+}
+if (!function_exists('ctype_upper')) {
+ function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
+}
+if (!function_exists('ctype_xdigit')) {
+ function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
+}
diff --git a/vendor/symfony/polyfill-ctype/composer.json b/vendor/symfony/polyfill-ctype/composer.json
new file mode 100644
index 0000000..ee5c931
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "symfony/polyfill-ctype",
+ "type": "library",
+ "description": "Symfony polyfill for ctype functions",
+ "keywords": ["polyfill", "compatibility", "portable", "ctype"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
+ "files": [ "bootstrap.php" ]
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/Idn.php b/vendor/symfony/polyfill-intl-idn/Idn.php
new file mode 100644
index 0000000..fee3026
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Idn.php
@@ -0,0 +1,925 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Intl\Idn;
+
+use Exception;
+use Normalizer;
+use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges;
+use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex;
+
+/**
+ * @see https://www.unicode.org/reports/tr46/
+ *
+ * @internal
+ */
+final class Idn
+{
+ public const ERROR_EMPTY_LABEL = 1;
+ public const ERROR_LABEL_TOO_LONG = 2;
+ public const ERROR_DOMAIN_NAME_TOO_LONG = 4;
+ public const ERROR_LEADING_HYPHEN = 8;
+ public const ERROR_TRAILING_HYPHEN = 0x10;
+ public const ERROR_HYPHEN_3_4 = 0x20;
+ public const ERROR_LEADING_COMBINING_MARK = 0x40;
+ public const ERROR_DISALLOWED = 0x80;
+ public const ERROR_PUNYCODE = 0x100;
+ public const ERROR_LABEL_HAS_DOT = 0x200;
+ public const ERROR_INVALID_ACE_LABEL = 0x400;
+ public const ERROR_BIDI = 0x800;
+ public const ERROR_CONTEXTJ = 0x1000;
+ public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;
+ public const ERROR_CONTEXTO_DIGITS = 0x4000;
+
+ public const INTL_IDNA_VARIANT_2003 = 0;
+ public const INTL_IDNA_VARIANT_UTS46 = 1;
+
+ public const IDNA_DEFAULT = 0;
+ public const IDNA_ALLOW_UNASSIGNED = 1;
+ public const IDNA_USE_STD3_RULES = 2;
+ public const IDNA_CHECK_BIDI = 4;
+ public const IDNA_CHECK_CONTEXTJ = 8;
+ public const IDNA_NONTRANSITIONAL_TO_ASCII = 16;
+ public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;
+
+ public const MAX_DOMAIN_SIZE = 253;
+ public const MAX_LABEL_SIZE = 63;
+
+ public const BASE = 36;
+ public const TMIN = 1;
+ public const TMAX = 26;
+ public const SKEW = 38;
+ public const DAMP = 700;
+ public const INITIAL_BIAS = 72;
+ public const INITIAL_N = 128;
+ public const DELIMITER = '-';
+ public const MAX_INT = 2147483647;
+
+ /**
+ * Contains the numeric value of a basic code point (for use in representing integers) in the
+ * range 0 to BASE-1, or -1 if b is does not represent a value.
+ *
+ * @var array<int, int>
+ */
+ private static $basicToDigit = [
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
+
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ ];
+
+ /**
+ * @var array<int, int>
+ */
+ private static $virama;
+
+ /**
+ * @var array<int, string>
+ */
+ private static $mapped;
+
+ /**
+ * @var array<int, bool>
+ */
+ private static $ignored;
+
+ /**
+ * @var array<int, string>
+ */
+ private static $deviation;
+
+ /**
+ * @var array<int, bool>
+ */
+ private static $disallowed;
+
+ /**
+ * @var array<int, string>
+ */
+ private static $disallowed_STD3_mapped;
+
+ /**
+ * @var array<int, bool>
+ */
+ private static $disallowed_STD3_valid;
+
+ /**
+ * @var bool
+ */
+ private static $mappingTableLoaded = false;
+
+ /**
+ * @see https://www.unicode.org/reports/tr46/#ToASCII
+ *
+ * @param string $domainName
+ * @param int $options
+ * @param int $variant
+ * @param array $idna_info
+ *
+ * @return string|false
+ */
+ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
+ {
+ if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
+ @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
+ }
+
+ $options = [
+ 'CheckHyphens' => true,
+ 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
+ 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
+ 'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
+ 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII),
+ 'VerifyDnsLength' => true,
+ ];
+ $info = new Info();
+ $labels = self::process((string) $domainName, $options, $info);
+
+ foreach ($labels as $i => $label) {
+ // Only convert labels to punycode that contain non-ASCII code points
+ if (1 === preg_match('/[^\x00-\x7F]/', $label)) {
+ try {
+ $label = 'xn--'.self::punycodeEncode($label);
+ } catch (Exception $e) {
+ $info->errors |= self::ERROR_PUNYCODE;
+ }
+
+ $labels[$i] = $label;
+ }
+ }
+
+ if ($options['VerifyDnsLength']) {
+ self::validateDomainAndLabelLength($labels, $info);
+ }
+
+ $idna_info = [
+ 'result' => implode('.', $labels),
+ 'isTransitionalDifferent' => $info->transitionalDifferent,
+ 'errors' => $info->errors,
+ ];
+
+ return 0 === $info->errors ? $idna_info['result'] : false;
+ }
+
+ /**
+ * @see https://www.unicode.org/reports/tr46/#ToUnicode
+ *
+ * @param string $domainName
+ * @param int $options
+ * @param int $variant
+ * @param array $idna_info
+ *
+ * @return string|false
+ */
+ public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])
+ {
+ if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) {
+ @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED);
+ }
+
+ $info = new Info();
+ $labels = self::process((string) $domainName, [
+ 'CheckHyphens' => true,
+ 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),
+ 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),
+ 'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),
+ 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE),
+ ], $info);
+ $idna_info = [
+ 'result' => implode('.', $labels),
+ 'isTransitionalDifferent' => $info->transitionalDifferent,
+ 'errors' => $info->errors,
+ ];
+
+ return 0 === $info->errors ? $idna_info['result'] : false;
+ }
+
+ /**
+ * @param string $label
+ *
+ * @return bool
+ */
+ private static function isValidContextJ(array $codePoints, $label)
+ {
+ if (!isset(self::$virama)) {
+ self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php';
+ }
+
+ $offset = 0;
+
+ foreach ($codePoints as $i => $codePoint) {
+ if (0x200C !== $codePoint && 0x200D !== $codePoint) {
+ continue;
+ }
+
+ if (!isset($codePoints[$i - 1])) {
+ return false;
+ }
+
+ // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True;
+ if (isset(self::$virama[$codePoints[$i - 1]])) {
+ continue;
+ }
+
+ // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then
+ // True;
+ // Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\u200C[Joining_Type:T]*)[Joining_Type:{R,D}]
+ if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \PREG_OFFSET_CAPTURE, $offset)) {
+ $offset += \strlen($matches[1][0]);
+
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap
+ *
+ * @param string $input
+ * @param array<string, bool> $options
+ *
+ * @return string
+ */
+ private static function mapCodePoints($input, array $options, Info $info)
+ {
+ $str = '';
+ $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
+ $transitional = $options['Transitional_Processing'];
+
+ foreach (self::utf8Decode($input) as $codePoint) {
+ $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
+
+ switch ($data['status']) {
+ case 'disallowed':
+ $info->errors |= self::ERROR_DISALLOWED;
+
+ // no break.
+
+ case 'valid':
+ $str .= mb_chr($codePoint, 'utf-8');
+
+ break;
+
+ case 'ignored':
+ // Do nothing.
+ break;
+
+ case 'mapped':
+ $str .= $data['mapping'];
+
+ break;
+
+ case 'deviation':
+ $info->transitionalDifferent = true;
+ $str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8'));
+
+ break;
+ }
+ }
+
+ return $str;
+ }
+
+ /**
+ * @see https://www.unicode.org/reports/tr46/#Processing
+ *
+ * @param string $domain
+ * @param array<string, bool> $options
+ *
+ * @return array<int, string>
+ */
+ private static function process($domain, array $options, Info $info)
+ {
+ // If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and
+ // we need to respect the VerifyDnsLength option.
+ $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'];
+
+ if ($checkForEmptyLabels && '' === $domain) {
+ $info->errors |= self::ERROR_EMPTY_LABEL;
+
+ return [$domain];
+ }
+
+ // Step 1. Map each code point in the domain name string
+ $domain = self::mapCodePoints($domain, $options, $info);
+
+ // Step 2. Normalize the domain name string to Unicode Normalization Form C.
+ if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) {
+ $domain = Normalizer::normalize($domain, Normalizer::FORM_C);
+ }
+
+ // Step 3. Break the string into labels at U+002E (.) FULL STOP.
+ $labels = explode('.', $domain);
+ $lastLabelIndex = \count($labels) - 1;
+
+ // Step 4. Convert and validate each label in the domain name string.
+ foreach ($labels as $i => $label) {
+ $validationOptions = $options;
+
+ if ('xn--' === substr($label, 0, 4)) {
+ try {
+ $label = self::punycodeDecode(substr($label, 4));
+ } catch (Exception $e) {
+ $info->errors |= self::ERROR_PUNYCODE;
+
+ continue;
+ }
+
+ $validationOptions['Transitional_Processing'] = false;
+ $labels[$i] = $label;
+ }
+
+ self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex);
+ }
+
+ if ($info->bidiDomain && !$info->validBidiDomain) {
+ $info->errors |= self::ERROR_BIDI;
+ }
+
+ // Any input domain name string that does not record an error has been successfully
+ // processed according to this specification. Conversely, if an input domain_name string
+ // causes an error, then the processing of the input domain_name string fails. Determining
+ // what to do with error input is up to the caller, and not in the scope of this document.
+ return $labels;
+ }
+
+ /**
+ * @see https://tools.ietf.org/html/rfc5893#section-2
+ *
+ * @param string $label
+ */
+ private static function validateBidiLabel($label, Info $info)
+ {
+ if (1 === preg_match(Regex::RTL_LABEL, $label)) {
+ $info->bidiDomain = true;
+
+ // Step 1. The first character must be a character with Bidi property L, R, or AL.
+ // If it has the R or AL property, it is an RTL label
+ if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ // Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES,
+ // CS, ET, ON, BN, or NSM are allowed.
+ if (1 === preg_match(Regex::BIDI_STEP_2, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ // Step 3. In an RTL label, the end of the label must be a character with Bidi property
+ // R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM.
+ if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa.
+ if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ return;
+ }
+
+ // We are a LTR label
+ // Step 1. The first character must be a character with Bidi property L, R, or AL.
+ // If it has the L property, it is an LTR label.
+ if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ // Step 5. In an LTR label, only characters with the Bidi properties L, EN,
+ // ES, CS, ET, ON, BN, or NSM are allowed.
+ if (1 === preg_match(Regex::BIDI_STEP_5, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+
+ // Step 6.In an LTR label, the end of the label must be a character with Bidi property L or
+ // EN, followed by zero or more characters with Bidi property NSM.
+ if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) {
+ $info->validBidiDomain = false;
+
+ return;
+ }
+ }
+
+ /**
+ * @param array<int, string> $labels
+ */
+ private static function validateDomainAndLabelLength(array $labels, Info $info)
+ {
+ $maxDomainSize = self::MAX_DOMAIN_SIZE;
+ $length = \count($labels);
+
+ // Number of "." delimiters.
+ $domainLength = $length - 1;
+
+ // If the last label is empty and it is not the first label, then it is the root label.
+ // Increase the max size by 1, making it 254, to account for the root label's "."
+ // delimiter. This also means we don't need to check the last label's length for being too
+ // long.
+ if ($length > 1 && '' === $labels[$length - 1]) {
+ ++$maxDomainSize;
+ --$length;
+ }
+
+ for ($i = 0; $i < $length; ++$i) {
+ $bytes = \strlen($labels[$i]);
+ $domainLength += $bytes;
+
+ if ($bytes > self::MAX_LABEL_SIZE) {
+ $info->errors |= self::ERROR_LABEL_TOO_LONG;
+ }
+ }
+
+ if ($domainLength > $maxDomainSize) {
+ $info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG;
+ }
+ }
+
+ /**
+ * @see https://www.unicode.org/reports/tr46/#Validity_Criteria
+ *
+ * @param string $label
+ * @param array<string, bool> $options
+ * @param bool $canBeEmpty
+ */
+ private static function validateLabel($label, Info $info, array $options, $canBeEmpty)
+ {
+ if ('' === $label) {
+ if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) {
+ $info->errors |= self::ERROR_EMPTY_LABEL;
+ }
+
+ return;
+ }
+
+ // Step 1. The label must be in Unicode Normalization Form C.
+ if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) {
+ $info->errors |= self::ERROR_INVALID_ACE_LABEL;
+ }
+
+ $codePoints = self::utf8Decode($label);
+
+ if ($options['CheckHyphens']) {
+ // Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
+ // in both the thrid and fourth positions.
+ if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) {
+ $info->errors |= self::ERROR_HYPHEN_3_4;
+ }
+
+ // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D
+ // HYPHEN-MINUS character.
+ if ('-' === substr($label, 0, 1)) {
+ $info->errors |= self::ERROR_LEADING_HYPHEN;
+ }
+
+ if ('-' === substr($label, -1, 1)) {
+ $info->errors |= self::ERROR_TRAILING_HYPHEN;
+ }
+ }
+
+ // Step 4. The label must not contain a U+002E (.) FULL STOP.
+ if (false !== strpos($label, '.')) {
+ $info->errors |= self::ERROR_LABEL_HAS_DOT;
+ }
+
+ // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark.
+ if (1 === preg_match(Regex::COMBINING_MARK, $label)) {
+ $info->errors |= self::ERROR_LEADING_COMBINING_MARK;
+ }
+
+ // Step 6. Each code point in the label must only have certain status values according to
+ // Section 5, IDNA Mapping Table:
+ $transitional = $options['Transitional_Processing'];
+ $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];
+
+ foreach ($codePoints as $codePoint) {
+ $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);
+ $status = $data['status'];
+
+ if ('valid' === $status || (!$transitional && 'deviation' === $status)) {
+ continue;
+ }
+
+ $info->errors |= self::ERROR_DISALLOWED;
+
+ break;
+ }
+
+ // Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in
+ // The Unicode Code Points and Internationalized Domain Names for Applications (IDNA)
+ // [IDNA2008].
+ if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) {
+ $info->errors |= self::ERROR_CONTEXTJ;
+ }
+
+ // Step 8. If CheckBidi, and if the domain name is a Bidi domain name, then the label must
+ // satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2.
+ if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) {
+ self::validateBidiLabel($label, $info);
+ }
+ }
+
+ /**
+ * @see https://tools.ietf.org/html/rfc3492#section-6.2
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ private static function punycodeDecode($input)
+ {
+ $n = self::INITIAL_N;
+ $out = 0;
+ $i = 0;
+ $bias = self::INITIAL_BIAS;
+ $lastDelimIndex = strrpos($input, self::DELIMITER);
+ $b = false === $lastDelimIndex ? 0 : $lastDelimIndex;
+ $inputLength = \strlen($input);
+ $output = [];
+ $bytes = array_map('ord', str_split($input));
+
+ for ($j = 0; $j < $b; ++$j) {
+ if ($bytes[$j] > 0x7F) {
+ throw new Exception('Invalid input');
+ }
+
+ $output[$out++] = $input[$j];
+ }
+
+ if ($b > 0) {
+ ++$b;
+ }
+
+ for ($in = $b; $in < $inputLength; ++$out) {
+ $oldi = $i;
+ $w = 1;
+
+ for ($k = self::BASE; /* no condition */; $k += self::BASE) {
+ if ($in >= $inputLength) {
+ throw new Exception('Invalid input');
+ }
+
+ $digit = self::$basicToDigit[$bytes[$in++] & 0xFF];
+
+ if ($digit < 0) {
+ throw new Exception('Invalid input');
+ }
+
+ if ($digit > intdiv(self::MAX_INT - $i, $w)) {
+ throw new Exception('Integer overflow');
+ }
+
+ $i += $digit * $w;
+
+ if ($k <= $bias) {
+ $t = self::TMIN;
+ } elseif ($k >= $bias + self::TMAX) {
+ $t = self::TMAX;
+ } else {
+ $t = $k - $bias;
+ }
+
+ if ($digit < $t) {
+ break;
+ }
+
+ $baseMinusT = self::BASE - $t;
+
+ if ($w > intdiv(self::MAX_INT, $baseMinusT)) {
+ throw new Exception('Integer overflow');
+ }
+
+ $w *= $baseMinusT;
+ }
+
+ $outPlusOne = $out + 1;
+ $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);
+
+ if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {
+ throw new Exception('Integer overflow');
+ }
+
+ $n += intdiv($i, $outPlusOne);
+ $i %= $outPlusOne;
+ array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]);
+ }
+
+ return implode('', $output);
+ }
+
+ /**
+ * @see https://tools.ietf.org/html/rfc3492#section-6.3
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ private static function punycodeEncode($input)
+ {
+ $n = self::INITIAL_N;
+ $delta = 0;
+ $out = 0;
+ $bias = self::INITIAL_BIAS;
+ $inputLength = 0;
+ $output = '';
+ $iter = self::utf8Decode($input);
+
+ foreach ($iter as $codePoint) {
+ ++$inputLength;
+
+ if ($codePoint < 0x80) {
+ $output .= \chr($codePoint);
+ ++$out;
+ }
+ }
+
+ $h = $out;
+ $b = $out;
+
+ if ($b > 0) {
+ $output .= self::DELIMITER;
+ ++$out;
+ }
+
+ while ($h < $inputLength) {
+ $m = self::MAX_INT;
+
+ foreach ($iter as $codePoint) {
+ if ($codePoint >= $n && $codePoint < $m) {
+ $m = $codePoint;
+ }
+ }
+
+ if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {
+ throw new Exception('Integer overflow');
+ }
+
+ $delta += ($m - $n) * ($h + 1);
+ $n = $m;
+
+ foreach ($iter as $codePoint) {
+ if ($codePoint < $n && 0 === ++$delta) {
+ throw new Exception('Integer overflow');
+ }
+
+ if ($codePoint === $n) {
+ $q = $delta;
+
+ for ($k = self::BASE; /* no condition */; $k += self::BASE) {
+ if ($k <= $bias) {
+ $t = self::TMIN;
+ } elseif ($k >= $bias + self::TMAX) {
+ $t = self::TMAX;
+ } else {
+ $t = $k - $bias;
+ }
+
+ if ($q < $t) {
+ break;
+ }
+
+ $qMinusT = $q - $t;
+ $baseMinusT = self::BASE - $t;
+ $output .= self::encodeDigit($t + ($qMinusT) % ($baseMinusT), false);
+ ++$out;
+ $q = intdiv($qMinusT, $baseMinusT);
+ }
+
+ $output .= self::encodeDigit($q, false);
+ ++$out;
+ $bias = self::adaptBias($delta, $h + 1, $h === $b);
+ $delta = 0;
+ ++$h;
+ }
+ }
+
+ ++$delta;
+ ++$n;
+ }
+
+ return $output;
+ }
+
+ /**
+ * @see https://tools.ietf.org/html/rfc3492#section-6.1
+ *
+ * @param int $delta
+ * @param int $numPoints
+ * @param bool $firstTime
+ *
+ * @return int
+ */
+ private static function adaptBias($delta, $numPoints, $firstTime)
+ {
+ // xxx >> 1 is a faster way of doing intdiv(xxx, 2)
+ $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1;
+ $delta += intdiv($delta, $numPoints);
+ $k = 0;
+
+ while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) {
+ $delta = intdiv($delta, self::BASE - self::TMIN);
+ $k += self::BASE;
+ }
+
+ return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW);
+ }
+
+ /**
+ * @param int $d
+ * @param bool $flag
+ *
+ * @return string
+ */
+ private static function encodeDigit($d, $flag)
+ {
+ return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5));
+ }
+
+ /**
+ * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any
+ * invalid byte sequences will be replaced by a U+FFFD replacement code point.
+ *
+ * @see https://encoding.spec.whatwg.org/#utf-8-decoder
+ *
+ * @param string $input
+ *
+ * @return array<int, int>
+ */
+ private static function utf8Decode($input)
+ {
+ $bytesSeen = 0;
+ $bytesNeeded = 0;
+ $lowerBoundary = 0x80;
+ $upperBoundary = 0xBF;
+ $codePoint = 0;
+ $codePoints = [];
+ $length = \strlen($input);
+
+ for ($i = 0; $i < $length; ++$i) {
+ $byte = \ord($input[$i]);
+
+ if (0 === $bytesNeeded) {
+ if ($byte >= 0x00 && $byte <= 0x7F) {
+ $codePoints[] = $byte;
+
+ continue;
+ }
+
+ if ($byte >= 0xC2 && $byte <= 0xDF) {
+ $bytesNeeded = 1;
+ $codePoint = $byte & 0x1F;
+ } elseif ($byte >= 0xE0 && $byte <= 0xEF) {
+ if (0xE0 === $byte) {
+ $lowerBoundary = 0xA0;
+ } elseif (0xED === $byte) {
+ $upperBoundary = 0x9F;
+ }
+
+ $bytesNeeded = 2;
+ $codePoint = $byte & 0xF;
+ } elseif ($byte >= 0xF0 && $byte <= 0xF4) {
+ if (0xF0 === $byte) {
+ $lowerBoundary = 0x90;
+ } elseif (0xF4 === $byte) {
+ $upperBoundary = 0x8F;
+ }
+
+ $bytesNeeded = 3;
+ $codePoint = $byte & 0x7;
+ } else {
+ $codePoints[] = 0xFFFD;
+ }
+
+ continue;
+ }
+
+ if ($byte < $lowerBoundary || $byte > $upperBoundary) {
+ $codePoint = 0;
+ $bytesNeeded = 0;
+ $bytesSeen = 0;
+ $lowerBoundary = 0x80;
+ $upperBoundary = 0xBF;
+ --$i;
+ $codePoints[] = 0xFFFD;
+
+ continue;
+ }
+
+ $lowerBoundary = 0x80;
+ $upperBoundary = 0xBF;
+ $codePoint = ($codePoint << 6) | ($byte & 0x3F);
+
+ if (++$bytesSeen !== $bytesNeeded) {
+ continue;
+ }
+
+ $codePoints[] = $codePoint;
+ $codePoint = 0;
+ $bytesNeeded = 0;
+ $bytesSeen = 0;
+ }
+
+ // String unexpectedly ended, so append a U+FFFD code point.
+ if (0 !== $bytesNeeded) {
+ $codePoints[] = 0xFFFD;
+ }
+
+ return $codePoints;
+ }
+
+ /**
+ * @param int $codePoint
+ * @param bool $useSTD3ASCIIRules
+ *
+ * @return array{status: string, mapping?: string}
+ */
+ private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules)
+ {
+ if (!self::$mappingTableLoaded) {
+ self::$mappingTableLoaded = true;
+ self::$mapped = require __DIR__.'/Resources/unidata/mapped.php';
+ self::$ignored = require __DIR__.'/Resources/unidata/ignored.php';
+ self::$deviation = require __DIR__.'/Resources/unidata/deviation.php';
+ self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php';
+ self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php';
+ self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php';
+ }
+
+ if (isset(self::$mapped[$codePoint])) {
+ return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]];
+ }
+
+ if (isset(self::$ignored[$codePoint])) {
+ return ['status' => 'ignored'];
+ }
+
+ if (isset(self::$deviation[$codePoint])) {
+ return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]];
+ }
+
+ if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) {
+ return ['status' => 'disallowed'];
+ }
+
+ $isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]);
+
+ if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) {
+ $status = 'disallowed';
+
+ if (!$useSTD3ASCIIRules) {
+ $status = $isDisallowedMapped ? 'mapped' : 'valid';
+ }
+
+ if ($isDisallowedMapped) {
+ return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]];
+ }
+
+ return ['status' => $status];
+ }
+
+ return ['status' => 'valid'];
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/Info.php b/vendor/symfony/polyfill-intl-idn/Info.php
new file mode 100644
index 0000000..25c3582
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Info.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Intl\Idn;
+
+/**
+ * @internal
+ */
+class Info
+{
+ public $bidiDomain = false;
+ public $errors = 0;
+ public $validBidiDomain = true;
+ public $transitionalDifferent = false;
+}
diff --git a/vendor/symfony/polyfill-intl-idn/LICENSE b/vendor/symfony/polyfill-intl-idn/LICENSE
new file mode 100644
index 0000000..03c5e25
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-2019 Fabien Potencier and Trevor Rowbotham <trevor.rowbotham@pm.me>
+
+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/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php
new file mode 100644
index 0000000..5bb70e4
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php
@@ -0,0 +1,375 @@
+<?php
+
+namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;
+
+/**
+ * @internal
+ */
+final class DisallowedRanges
+{
+ /**
+ * @param int $codePoint
+ *
+ * @return bool
+ */
+ public static function inRange($codePoint)
+ {
+ if ($codePoint >= 128 && $codePoint <= 159) {
+ return true;
+ }
+
+ if ($codePoint >= 2155 && $codePoint <= 2207) {
+ return true;
+ }
+
+ if ($codePoint >= 3676 && $codePoint <= 3712) {
+ return true;
+ }
+
+ if ($codePoint >= 3808 && $codePoint <= 3839) {
+ return true;
+ }
+
+ if ($codePoint >= 4059 && $codePoint <= 4095) {
+ return true;
+ }
+
+ if ($codePoint >= 4256 && $codePoint <= 4293) {
+ return true;
+ }
+
+ if ($codePoint >= 6849 && $codePoint <= 6911) {
+ return true;
+ }
+
+ if ($codePoint >= 11859 && $codePoint <= 11903) {
+ return true;
+ }
+
+ if ($codePoint >= 42955 && $codePoint <= 42996) {
+ return true;
+ }
+
+ if ($codePoint >= 55296 && $codePoint <= 57343) {
+ return true;
+ }
+
+ if ($codePoint >= 57344 && $codePoint <= 63743) {
+ return true;
+ }
+
+ if ($codePoint >= 64218 && $codePoint <= 64255) {
+ return true;
+ }
+
+ if ($codePoint >= 64976 && $codePoint <= 65007) {
+ return true;
+ }
+
+ if ($codePoint >= 65630 && $codePoint <= 65663) {
+ return true;
+ }
+
+ if ($codePoint >= 65953 && $codePoint <= 65999) {
+ return true;
+ }
+
+ if ($codePoint >= 66046 && $codePoint <= 66175) {
+ return true;
+ }
+
+ if ($codePoint >= 66518 && $codePoint <= 66559) {
+ return true;
+ }
+
+ if ($codePoint >= 66928 && $codePoint <= 67071) {
+ return true;
+ }
+
+ if ($codePoint >= 67432 && $codePoint <= 67583) {
+ return true;
+ }
+
+ if ($codePoint >= 67760 && $codePoint <= 67807) {
+ return true;
+ }
+
+ if ($codePoint >= 67904 && $codePoint <= 67967) {
+ return true;
+ }
+
+ if ($codePoint >= 68256 && $codePoint <= 68287) {
+ return true;
+ }
+
+ if ($codePoint >= 68528 && $codePoint <= 68607) {
+ return true;
+ }
+
+ if ($codePoint >= 68681 && $codePoint <= 68735) {
+ return true;
+ }
+
+ if ($codePoint >= 68922 && $codePoint <= 69215) {
+ return true;
+ }
+
+ if ($codePoint >= 69298 && $codePoint <= 69375) {
+ return true;
+ }
+
+ if ($codePoint >= 69466 && $codePoint <= 69551) {
+ return true;
+ }
+
+ if ($codePoint >= 70207 && $codePoint <= 70271) {
+ return true;
+ }
+
+ if ($codePoint >= 70517 && $codePoint <= 70655) {
+ return true;
+ }
+
+ if ($codePoint >= 70874 && $codePoint <= 71039) {
+ return true;
+ }
+
+ if ($codePoint >= 71134 && $codePoint <= 71167) {
+ return true;
+ }
+
+ if ($codePoint >= 71370 && $codePoint <= 71423) {
+ return true;
+ }
+
+ if ($codePoint >= 71488 && $codePoint <= 71679) {
+ return true;
+ }
+
+ if ($codePoint >= 71740 && $codePoint <= 71839) {
+ return true;
+ }
+
+ if ($codePoint >= 72026 && $codePoint <= 72095) {
+ return true;
+ }
+
+ if ($codePoint >= 72441 && $codePoint <= 72703) {
+ return true;
+ }
+
+ if ($codePoint >= 72887 && $codePoint <= 72959) {
+ return true;
+ }
+
+ if ($codePoint >= 73130 && $codePoint <= 73439) {
+ return true;
+ }
+
+ if ($codePoint >= 73465 && $codePoint <= 73647) {
+ return true;
+ }
+
+ if ($codePoint >= 74650 && $codePoint <= 74751) {
+ return true;
+ }
+
+ if ($codePoint >= 75076 && $codePoint <= 77823) {
+ return true;
+ }
+
+ if ($codePoint >= 78905 && $codePoint <= 82943) {
+ return true;
+ }
+
+ if ($codePoint >= 83527 && $codePoint <= 92159) {
+ return true;
+ }
+
+ if ($codePoint >= 92784 && $codePoint <= 92879) {
+ return true;
+ }
+
+ if ($codePoint >= 93072 && $codePoint <= 93759) {
+ return true;
+ }
+
+ if ($codePoint >= 93851 && $codePoint <= 93951) {
+ return true;
+ }
+
+ if ($codePoint >= 94112 && $codePoint <= 94175) {
+ return true;
+ }
+
+ if ($codePoint >= 101590 && $codePoint <= 101631) {
+ return true;
+ }
+
+ if ($codePoint >= 101641 && $codePoint <= 110591) {
+ return true;
+ }
+
+ if ($codePoint >= 110879 && $codePoint <= 110927) {
+ return true;
+ }
+
+ if ($codePoint >= 111356 && $codePoint <= 113663) {
+ return true;
+ }
+
+ if ($codePoint >= 113828 && $codePoint <= 118783) {
+ return true;
+ }
+
+ if ($codePoint >= 119366 && $codePoint <= 119519) {
+ return true;
+ }
+
+ if ($codePoint >= 119673 && $codePoint <= 119807) {
+ return true;
+ }
+
+ if ($codePoint >= 121520 && $codePoint <= 122879) {
+ return true;
+ }
+
+ if ($codePoint >= 122923 && $codePoint <= 123135) {
+ return true;
+ }
+
+ if ($codePoint >= 123216 && $codePoint <= 123583) {
+ return true;
+ }
+
+ if ($codePoint >= 123648 && $codePoint <= 124927) {
+ return true;
+ }
+
+ if ($codePoint >= 125143 && $codePoint <= 125183) {
+ return true;
+ }
+
+ if ($codePoint >= 125280 && $codePoint <= 126064) {
+ return true;
+ }
+
+ if ($codePoint >= 126133 && $codePoint <= 126208) {
+ return true;
+ }
+
+ if ($codePoint >= 126270 && $codePoint <= 126463) {
+ return true;
+ }
+
+ if ($codePoint >= 126652 && $codePoint <= 126703) {
+ return true;
+ }
+
+ if ($codePoint >= 126706 && $codePoint <= 126975) {
+ return true;
+ }
+
+ if ($codePoint >= 127406 && $codePoint <= 127461) {
+ return true;
+ }
+
+ if ($codePoint >= 127590 && $codePoint <= 127743) {
+ return true;
+ }
+
+ if ($codePoint >= 129202 && $codePoint <= 129279) {
+ return true;
+ }
+
+ if ($codePoint >= 129751 && $codePoint <= 129791) {
+ return true;
+ }
+
+ if ($codePoint >= 129995 && $codePoint <= 130031) {
+ return true;
+ }
+
+ if ($codePoint >= 130042 && $codePoint <= 131069) {
+ return true;
+ }
+
+ if ($codePoint >= 173790 && $codePoint <= 173823) {
+ return true;
+ }
+
+ if ($codePoint >= 191457 && $codePoint <= 194559) {
+ return true;
+ }
+
+ if ($codePoint >= 195102 && $codePoint <= 196605) {
+ return true;
+ }
+
+ if ($codePoint >= 201547 && $codePoint <= 262141) {
+ return true;
+ }
+
+ if ($codePoint >= 262144 && $codePoint <= 327677) {
+ return true;
+ }
+
+ if ($codePoint >= 327680 && $codePoint <= 393213) {
+ return true;
+ }
+
+ if ($codePoint >= 393216 && $codePoint <= 458749) {
+ return true;
+ }
+
+ if ($codePoint >= 458752 && $codePoint <= 524285) {
+ return true;
+ }
+
+ if ($codePoint >= 524288 && $codePoint <= 589821) {
+ return true;
+ }
+
+ if ($codePoint >= 589824 && $codePoint <= 655357) {
+ return true;
+ }
+
+ if ($codePoint >= 655360 && $codePoint <= 720893) {
+ return true;
+ }
+
+ if ($codePoint >= 720896 && $codePoint <= 786429) {
+ return true;
+ }
+
+ if ($codePoint >= 786432 && $codePoint <= 851965) {
+ return true;
+ }
+
+ if ($codePoint >= 851968 && $codePoint <= 917501) {
+ return true;
+ }
+
+ if ($codePoint >= 917536 && $codePoint <= 917631) {
+ return true;
+ }
+
+ if ($codePoint >= 917632 && $codePoint <= 917759) {
+ return true;
+ }
+
+ if ($codePoint >= 918000 && $codePoint <= 983037) {
+ return true;
+ }
+
+ if ($codePoint >= 983040 && $codePoint <= 1048573) {
+ return true;
+ }
+
+ if ($codePoint >= 1048576 && $codePoint <= 1114109) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php
new file mode 100644
index 0000000..5c1c51d
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Symfony\Polyfill\Intl\Idn\Resources\unidata;
+
+/**
+ * @internal
+ */
+final class Regex
+{
+ const COMBINING_MARK = '/^[\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{0903}\x{093A}\x{093B}\x{093C}\x{093E}-\x{0940}\x{0941}-\x{0948}\x{0949}-\x{094C}\x{094D}\x{094E}-\x{094F}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{0982}-\x{0983}\x{09BC}\x{09BE}-\x{09C0}\x{09C1}-\x{09C4}\x{09C7}-\x{09C8}\x{09CB}-\x{09CC}\x{09CD}\x{09D7}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A03}\x{0A3C}\x{0A3E}-\x{0A40}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0A83}\x{0ABC}\x{0ABE}-\x{0AC0}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0AC9}\x{0ACB}-\x{0ACC}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B02}-\x{0B03}\x{0B3C}\x{0B3E}\x{0B3F}\x{0B40}\x{0B41}-\x{0B44}\x{0B47}-\x{0B48}\x{0B4B}-\x{0B4C}\x{0B4D}\x{0B55}-\x{0B56}\x{0B57}\x{0B62}-\x{0B63}\x{0B82}\x{0BBE}-\x{0BBF}\x{0BC0}\x{0BC1}-\x{0BC2}\x{0BC6}-\x{0BC8}\x{0BCA}-\x{0BCC}\x{0BCD}\x{0BD7}\x{0C00}\x{0C01}-\x{0C03}\x{0C04}\x{0C3E}-\x{0C40}\x{0C41}-\x{0C44}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0C82}-\x{0C83}\x{0CBC}\x{0CBE}\x{0CBF}\x{0CC0}-\x{0CC4}\x{0CC6}\x{0CC7}-\x{0CC8}\x{0CCA}-\x{0CCB}\x{0CCC}-\x{0CCD}\x{0CD5}-\x{0CD6}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D02}-\x{0D03}\x{0D3B}-\x{0D3C}\x{0D3E}-\x{0D40}\x{0D41}-\x{0D44}\x{0D46}-\x{0D48}\x{0D4A}-\x{0D4C}\x{0D4D}\x{0D57}\x{0D62}-\x{0D63}\x{0D81}\x{0D82}-\x{0D83}\x{0DCA}\x{0DCF}-\x{0DD1}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0DD8}-\x{0DDF}\x{0DF2}-\x{0DF3}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3E}-\x{0F3F}\x{0F71}-\x{0F7E}\x{0F7F}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102B}-\x{102C}\x{102D}-\x{1030}\x{1031}\x{1032}-\x{1037}\x{1038}\x{1039}-\x{103A}\x{103B}-\x{103C}\x{103D}-\x{103E}\x{1056}-\x{1057}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1062}-\x{1064}\x{1067}-\x{106D}\x{1071}-\x{1074}\x{1082}\x{1083}-\x{1084}\x{1085}-\x{1086}\x{1087}-\x{108C}\x{108D}\x{108F}\x{109A}-\x{109C}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B6}\x{17B7}-\x{17BD}\x{17BE}-\x{17C5}\x{17C6}\x{17C7}-\x{17C8}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1923}-\x{1926}\x{1927}-\x{1928}\x{1929}-\x{192B}\x{1930}-\x{1931}\x{1932}\x{1933}-\x{1938}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A19}-\x{1A1A}\x{1A1B}\x{1A55}\x{1A56}\x{1A57}\x{1A58}-\x{1A5E}\x{1A60}\x{1A61}\x{1A62}\x{1A63}-\x{1A64}\x{1A65}-\x{1A6C}\x{1A6D}-\x{1A72}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B04}\x{1B34}\x{1B35}\x{1B36}-\x{1B3A}\x{1B3B}\x{1B3C}\x{1B3D}-\x{1B41}\x{1B42}\x{1B43}-\x{1B44}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1B82}\x{1BA1}\x{1BA2}-\x{1BA5}\x{1BA6}-\x{1BA7}\x{1BA8}-\x{1BA9}\x{1BAA}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE7}\x{1BE8}-\x{1BE9}\x{1BEA}-\x{1BEC}\x{1BED}\x{1BEE}\x{1BEF}-\x{1BF1}\x{1BF2}-\x{1BF3}\x{1C24}-\x{1C2B}\x{1C2C}-\x{1C33}\x{1C34}-\x{1C35}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE1}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF7}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{302E}-\x{302F}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A823}-\x{A824}\x{A825}-\x{A826}\x{A827}\x{A82C}\x{A880}-\x{A881}\x{A8B4}-\x{A8C3}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A952}-\x{A953}\x{A980}-\x{A982}\x{A983}\x{A9B3}\x{A9B4}-\x{A9B5}\x{A9B6}-\x{A9B9}\x{A9BA}-\x{A9BB}\x{A9BC}-\x{A9BD}\x{A9BE}-\x{A9C0}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA2F}-\x{AA30}\x{AA31}-\x{AA32}\x{AA33}-\x{AA34}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA4D}\x{AA7B}\x{AA7C}\x{AA7D}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEB}\x{AAEC}-\x{AAED}\x{AAEE}-\x{AAEF}\x{AAF5}\x{AAF6}\x{ABE3}-\x{ABE4}\x{ABE5}\x{ABE6}-\x{ABE7}\x{ABE8}\x{ABE9}-\x{ABEA}\x{ABEC}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11000}\x{11001}\x{11002}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{11082}\x{110B0}-\x{110B2}\x{110B3}-\x{110B6}\x{110B7}-\x{110B8}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112C}\x{1112D}-\x{11134}\x{11145}-\x{11146}\x{11173}\x{11180}-\x{11181}\x{11182}\x{111B3}-\x{111B5}\x{111B6}-\x{111BE}\x{111BF}-\x{111C0}\x{111C9}-\x{111CC}\x{111CE}\x{111CF}\x{1122C}-\x{1122E}\x{1122F}-\x{11231}\x{11232}-\x{11233}\x{11234}\x{11235}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E0}-\x{112E2}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{11302}-\x{11303}\x{1133B}-\x{1133C}\x{1133E}-\x{1133F}\x{11340}\x{11341}-\x{11344}\x{11347}-\x{11348}\x{1134B}-\x{1134D}\x{11357}\x{11362}-\x{11363}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11435}-\x{11437}\x{11438}-\x{1143F}\x{11440}-\x{11441}\x{11442}-\x{11444}\x{11445}\x{11446}\x{1145E}\x{114B0}-\x{114B2}\x{114B3}-\x{114B8}\x{114B9}\x{114BA}\x{114BB}-\x{114BE}\x{114BF}-\x{114C0}\x{114C1}\x{114C2}-\x{114C3}\x{115AF}-\x{115B1}\x{115B2}-\x{115B5}\x{115B8}-\x{115BB}\x{115BC}-\x{115BD}\x{115BE}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11630}-\x{11632}\x{11633}-\x{1163A}\x{1163B}-\x{1163C}\x{1163D}\x{1163E}\x{1163F}-\x{11640}\x{116AB}\x{116AC}\x{116AD}\x{116AE}-\x{116AF}\x{116B0}-\x{116B5}\x{116B6}\x{116B7}\x{1171D}-\x{1171F}\x{11720}-\x{11721}\x{11722}-\x{11725}\x{11726}\x{11727}-\x{1172B}\x{1182C}-\x{1182E}\x{1182F}-\x{11837}\x{11838}\x{11839}-\x{1183A}\x{11930}-\x{11935}\x{11937}-\x{11938}\x{1193B}-\x{1193C}\x{1193D}\x{1193E}\x{11940}\x{11942}\x{11943}\x{119D1}-\x{119D3}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119DC}-\x{119DF}\x{119E0}\x{119E4}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A39}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A57}-\x{11A58}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A97}\x{11A98}-\x{11A99}\x{11C2F}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3E}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CA9}\x{11CAA}-\x{11CB0}\x{11CB1}\x{11CB2}-\x{11CB3}\x{11CB4}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D8A}-\x{11D8E}\x{11D90}-\x{11D91}\x{11D93}-\x{11D94}\x{11D95}\x{11D96}\x{11D97}\x{11EF3}-\x{11EF4}\x{11EF5}-\x{11EF6}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F51}-\x{16F87}\x{16F8F}-\x{16F92}\x{16FE4}\x{16FF0}-\x{16FF1}\x{1BC9D}-\x{1BC9E}\x{1D165}-\x{1D166}\x{1D167}-\x{1D169}\x{1D16D}-\x{1D172}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]/u';
+
+ const RTL_LABEL = '/[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
+
+ const BIDI_STEP_1_LTR = '/^[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
+ const BIDI_STEP_1_RTL = '/^[\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{200F}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
+ const BIDI_STEP_2 = '/[^\x{0000}-\x{0008}\x{000E}-\x{001B}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{0030}-\x{0039}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B2}-\x{00B3}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00B9}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{2060}-\x{2064}\x{2065}\x{206A}-\x{206F}\x{2070}\x{2074}-\x{2079}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{2080}-\x{2089}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{2488}-\x{249B}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF10}-\x{FF19}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{102E1}-\x{102FB}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1D7CE}-\x{1D7FF}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F100}-\x{1F10A}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FBF0}-\x{1FBF9}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}]/u';
+ const BIDI_STEP_3 = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06F0}-\x{06F9}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{200F}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1D7CE}-\x{1D7FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';
+ const BIDI_STEP_4_AN = '/[\x{0600}-\x{0605}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{06DD}\x{08E2}\x{10D30}-\x{10D39}\x{10E60}-\x{10E7E}]/u';
+ const BIDI_STEP_4_EN = '/[\x{0030}-\x{0039}\x{00B2}-\x{00B3}\x{00B9}\x{06F0}-\x{06F9}\x{2070}\x{2074}-\x{2079}\x{2080}-\x{2089}\x{2488}-\x{249B}\x{FF10}-\x{FF19}\x{102E1}-\x{102FB}\x{1D7CE}-\x{1D7FF}\x{1F100}-\x{1F10A}\x{1FBF0}-\x{1FBF9}]/u';
+ const BIDI_STEP_5 = '/[\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0085}\x{0590}\x{05BE}\x{05C0}\x{05C3}\x{05C6}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0608}\x{060B}\x{060D}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{0660}-\x{0669}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06DD}\x{06E5}-\x{06E6}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0712}-\x{072F}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07F4}-\x{07F5}\x{07FA}\x{07FB}-\x{07FC}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{081A}\x{0824}\x{0828}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08E2}\x{1680}\x{2000}-\x{200A}\x{200F}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{205F}\x{2066}\x{2067}\x{2068}\x{2069}\x{3000}\x{FB1D}\x{FB1F}-\x{FB28}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFE}-\x{FDFF}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A04}\x{10A07}-\x{10A0B}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A3B}-\x{10A3E}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}]/u';
+ const BIDI_STEP_6 = '/[^\x{0000}-\x{0008}\x{0009}\x{000A}\x{000B}\x{000C}\x{000D}\x{000E}-\x{001B}\x{001C}-\x{001E}\x{001F}\x{0020}\x{0021}-\x{0022}\x{0023}\x{0024}\x{0025}\x{0026}-\x{0027}\x{0028}\x{0029}\x{002A}\x{002B}\x{002C}\x{002D}\x{002E}-\x{002F}\x{003A}\x{003B}\x{003C}-\x{003E}\x{003F}-\x{0040}\x{005B}\x{005C}\x{005D}\x{005E}\x{005F}\x{0060}\x{007B}\x{007C}\x{007D}\x{007E}\x{007F}-\x{0084}\x{0085}\x{0086}-\x{009F}\x{00A0}\x{00A1}\x{00A2}-\x{00A5}\x{00A6}\x{00A7}\x{00A8}\x{00A9}\x{00AB}\x{00AC}\x{00AD}\x{00AE}\x{00AF}\x{00B0}\x{00B1}\x{00B4}\x{00B6}-\x{00B7}\x{00B8}\x{00BB}\x{00BC}-\x{00BE}\x{00BF}\x{00D7}\x{00F7}\x{02B9}-\x{02BA}\x{02C2}-\x{02C5}\x{02C6}-\x{02CF}\x{02D2}-\x{02DF}\x{02E5}-\x{02EB}\x{02EC}\x{02ED}\x{02EF}-\x{02FF}\x{0300}-\x{036F}\x{0374}\x{0375}\x{037E}\x{0384}-\x{0385}\x{0387}\x{03F6}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{058A}\x{058D}-\x{058E}\x{058F}\x{0590}\x{0591}-\x{05BD}\x{05BE}\x{05BF}\x{05C0}\x{05C1}-\x{05C2}\x{05C3}\x{05C4}-\x{05C5}\x{05C6}\x{05C7}\x{05C8}-\x{05CF}\x{05D0}-\x{05EA}\x{05EB}-\x{05EE}\x{05EF}-\x{05F2}\x{05F3}-\x{05F4}\x{05F5}-\x{05FF}\x{0600}-\x{0605}\x{0606}-\x{0607}\x{0608}\x{0609}-\x{060A}\x{060B}\x{060C}\x{060D}\x{060E}-\x{060F}\x{0610}-\x{061A}\x{061B}\x{061C}\x{061D}\x{061E}-\x{061F}\x{0620}-\x{063F}\x{0640}\x{0641}-\x{064A}\x{064B}-\x{065F}\x{0660}-\x{0669}\x{066A}\x{066B}-\x{066C}\x{066D}\x{066E}-\x{066F}\x{0670}\x{0671}-\x{06D3}\x{06D4}\x{06D5}\x{06D6}-\x{06DC}\x{06DD}\x{06DE}\x{06DF}-\x{06E4}\x{06E5}-\x{06E6}\x{06E7}-\x{06E8}\x{06E9}\x{06EA}-\x{06ED}\x{06EE}-\x{06EF}\x{06FA}-\x{06FC}\x{06FD}-\x{06FE}\x{06FF}\x{0700}-\x{070D}\x{070E}\x{070F}\x{0710}\x{0711}\x{0712}-\x{072F}\x{0730}-\x{074A}\x{074B}-\x{074C}\x{074D}-\x{07A5}\x{07A6}-\x{07B0}\x{07B1}\x{07B2}-\x{07BF}\x{07C0}-\x{07C9}\x{07CA}-\x{07EA}\x{07EB}-\x{07F3}\x{07F4}-\x{07F5}\x{07F6}\x{07F7}-\x{07F9}\x{07FA}\x{07FB}-\x{07FC}\x{07FD}\x{07FE}-\x{07FF}\x{0800}-\x{0815}\x{0816}-\x{0819}\x{081A}\x{081B}-\x{0823}\x{0824}\x{0825}-\x{0827}\x{0828}\x{0829}-\x{082D}\x{082E}-\x{082F}\x{0830}-\x{083E}\x{083F}\x{0840}-\x{0858}\x{0859}-\x{085B}\x{085C}-\x{085D}\x{085E}\x{085F}\x{0860}-\x{086A}\x{086B}-\x{086F}\x{0870}-\x{089F}\x{08A0}-\x{08B4}\x{08B5}\x{08B6}-\x{08C7}\x{08C8}-\x{08D2}\x{08D3}-\x{08E1}\x{08E2}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09F2}-\x{09F3}\x{09FB}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AF1}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0BF3}-\x{0BF8}\x{0BF9}\x{0BFA}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C78}-\x{0C7E}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E3F}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F3A}\x{0F3B}\x{0F3C}\x{0F3D}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1390}-\x{1399}\x{1400}\x{1680}\x{169B}\x{169C}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DB}\x{17DD}\x{17F0}-\x{17F9}\x{1800}-\x{1805}\x{1806}\x{1807}-\x{180A}\x{180B}-\x{180D}\x{180E}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1940}\x{1944}-\x{1945}\x{19DE}-\x{19FF}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{1FBD}\x{1FBF}-\x{1FC1}\x{1FCD}-\x{1FCF}\x{1FDD}-\x{1FDF}\x{1FED}-\x{1FEF}\x{1FFD}-\x{1FFE}\x{2000}-\x{200A}\x{200B}-\x{200D}\x{200F}\x{2010}-\x{2015}\x{2016}-\x{2017}\x{2018}\x{2019}\x{201A}\x{201B}-\x{201C}\x{201D}\x{201E}\x{201F}\x{2020}-\x{2027}\x{2028}\x{2029}\x{202A}\x{202B}\x{202C}\x{202D}\x{202E}\x{202F}\x{2030}-\x{2034}\x{2035}-\x{2038}\x{2039}\x{203A}\x{203B}-\x{203E}\x{203F}-\x{2040}\x{2041}-\x{2043}\x{2044}\x{2045}\x{2046}\x{2047}-\x{2051}\x{2052}\x{2053}\x{2054}\x{2055}-\x{205E}\x{205F}\x{2060}-\x{2064}\x{2065}\x{2066}\x{2067}\x{2068}\x{2069}\x{206A}-\x{206F}\x{207A}-\x{207B}\x{207C}\x{207D}\x{207E}\x{208A}-\x{208B}\x{208C}\x{208D}\x{208E}\x{20A0}-\x{20BF}\x{20C0}-\x{20CF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2100}-\x{2101}\x{2103}-\x{2106}\x{2108}-\x{2109}\x{2114}\x{2116}-\x{2117}\x{2118}\x{211E}-\x{2123}\x{2125}\x{2127}\x{2129}\x{212E}\x{213A}-\x{213B}\x{2140}-\x{2144}\x{214A}\x{214B}\x{214C}-\x{214D}\x{2150}-\x{215F}\x{2189}\x{218A}-\x{218B}\x{2190}-\x{2194}\x{2195}-\x{2199}\x{219A}-\x{219B}\x{219C}-\x{219F}\x{21A0}\x{21A1}-\x{21A2}\x{21A3}\x{21A4}-\x{21A5}\x{21A6}\x{21A7}-\x{21AD}\x{21AE}\x{21AF}-\x{21CD}\x{21CE}-\x{21CF}\x{21D0}-\x{21D1}\x{21D2}\x{21D3}\x{21D4}\x{21D5}-\x{21F3}\x{21F4}-\x{2211}\x{2212}\x{2213}\x{2214}-\x{22FF}\x{2300}-\x{2307}\x{2308}\x{2309}\x{230A}\x{230B}\x{230C}-\x{231F}\x{2320}-\x{2321}\x{2322}-\x{2328}\x{2329}\x{232A}\x{232B}-\x{2335}\x{237B}\x{237C}\x{237D}-\x{2394}\x{2396}-\x{239A}\x{239B}-\x{23B3}\x{23B4}-\x{23DB}\x{23DC}-\x{23E1}\x{23E2}-\x{2426}\x{2440}-\x{244A}\x{2460}-\x{2487}\x{24EA}-\x{24FF}\x{2500}-\x{25B6}\x{25B7}\x{25B8}-\x{25C0}\x{25C1}\x{25C2}-\x{25F7}\x{25F8}-\x{25FF}\x{2600}-\x{266E}\x{266F}\x{2670}-\x{26AB}\x{26AD}-\x{2767}\x{2768}\x{2769}\x{276A}\x{276B}\x{276C}\x{276D}\x{276E}\x{276F}\x{2770}\x{2771}\x{2772}\x{2773}\x{2774}\x{2775}\x{2776}-\x{2793}\x{2794}-\x{27BF}\x{27C0}-\x{27C4}\x{27C5}\x{27C6}\x{27C7}-\x{27E5}\x{27E6}\x{27E7}\x{27E8}\x{27E9}\x{27EA}\x{27EB}\x{27EC}\x{27ED}\x{27EE}\x{27EF}\x{27F0}-\x{27FF}\x{2900}-\x{2982}\x{2983}\x{2984}\x{2985}\x{2986}\x{2987}\x{2988}\x{2989}\x{298A}\x{298B}\x{298C}\x{298D}\x{298E}\x{298F}\x{2990}\x{2991}\x{2992}\x{2993}\x{2994}\x{2995}\x{2996}\x{2997}\x{2998}\x{2999}-\x{29D7}\x{29D8}\x{29D9}\x{29DA}\x{29DB}\x{29DC}-\x{29FB}\x{29FC}\x{29FD}\x{29FE}-\x{2AFF}\x{2B00}-\x{2B2F}\x{2B30}-\x{2B44}\x{2B45}-\x{2B46}\x{2B47}-\x{2B4C}\x{2B4D}-\x{2B73}\x{2B76}-\x{2B95}\x{2B97}-\x{2BFF}\x{2CE5}-\x{2CEA}\x{2CEF}-\x{2CF1}\x{2CF9}-\x{2CFC}\x{2CFD}\x{2CFE}-\x{2CFF}\x{2D7F}\x{2DE0}-\x{2DFF}\x{2E00}-\x{2E01}\x{2E02}\x{2E03}\x{2E04}\x{2E05}\x{2E06}-\x{2E08}\x{2E09}\x{2E0A}\x{2E0B}\x{2E0C}\x{2E0D}\x{2E0E}-\x{2E16}\x{2E17}\x{2E18}-\x{2E19}\x{2E1A}\x{2E1B}\x{2E1C}\x{2E1D}\x{2E1E}-\x{2E1F}\x{2E20}\x{2E21}\x{2E22}\x{2E23}\x{2E24}\x{2E25}\x{2E26}\x{2E27}\x{2E28}\x{2E29}\x{2E2A}-\x{2E2E}\x{2E2F}\x{2E30}-\x{2E39}\x{2E3A}-\x{2E3B}\x{2E3C}-\x{2E3F}\x{2E40}\x{2E41}\x{2E42}\x{2E43}-\x{2E4F}\x{2E50}-\x{2E51}\x{2E52}\x{2E80}-\x{2E99}\x{2E9B}-\x{2EF3}\x{2F00}-\x{2FD5}\x{2FF0}-\x{2FFB}\x{3000}\x{3001}-\x{3003}\x{3004}\x{3008}\x{3009}\x{300A}\x{300B}\x{300C}\x{300D}\x{300E}\x{300F}\x{3010}\x{3011}\x{3012}-\x{3013}\x{3014}\x{3015}\x{3016}\x{3017}\x{3018}\x{3019}\x{301A}\x{301B}\x{301C}\x{301D}\x{301E}-\x{301F}\x{3020}\x{302A}-\x{302D}\x{3030}\x{3036}-\x{3037}\x{303D}\x{303E}-\x{303F}\x{3099}-\x{309A}\x{309B}-\x{309C}\x{30A0}\x{30FB}\x{31C0}-\x{31E3}\x{321D}-\x{321E}\x{3250}\x{3251}-\x{325F}\x{327C}-\x{327E}\x{32B1}-\x{32BF}\x{32CC}-\x{32CF}\x{3377}-\x{337A}\x{33DE}-\x{33DF}\x{33FF}\x{4DC0}-\x{4DFF}\x{A490}-\x{A4C6}\x{A60D}-\x{A60F}\x{A66F}\x{A670}-\x{A672}\x{A673}\x{A674}-\x{A67D}\x{A67E}\x{A67F}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A700}-\x{A716}\x{A717}-\x{A71F}\x{A720}-\x{A721}\x{A788}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A828}-\x{A82B}\x{A82C}\x{A838}\x{A839}\x{A874}-\x{A877}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{AB6A}-\x{AB6B}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1D}\x{FB1E}\x{FB1F}-\x{FB28}\x{FB29}\x{FB2A}-\x{FB36}\x{FB37}\x{FB38}-\x{FB3C}\x{FB3D}\x{FB3E}\x{FB3F}\x{FB40}-\x{FB41}\x{FB42}\x{FB43}-\x{FB44}\x{FB45}\x{FB46}-\x{FB4F}\x{FB50}-\x{FBB1}\x{FBB2}-\x{FBC1}\x{FBC2}-\x{FBD2}\x{FBD3}-\x{FD3D}\x{FD3E}\x{FD3F}\x{FD40}-\x{FD4F}\x{FD50}-\x{FD8F}\x{FD90}-\x{FD91}\x{FD92}-\x{FDC7}\x{FDC8}-\x{FDCF}\x{FDD0}-\x{FDEF}\x{FDF0}-\x{FDFB}\x{FDFC}\x{FDFD}\x{FDFE}-\x{FDFF}\x{FE00}-\x{FE0F}\x{FE10}-\x{FE16}\x{FE17}\x{FE18}\x{FE19}\x{FE20}-\x{FE2F}\x{FE30}\x{FE31}-\x{FE32}\x{FE33}-\x{FE34}\x{FE35}\x{FE36}\x{FE37}\x{FE38}\x{FE39}\x{FE3A}\x{FE3B}\x{FE3C}\x{FE3D}\x{FE3E}\x{FE3F}\x{FE40}\x{FE41}\x{FE42}\x{FE43}\x{FE44}\x{FE45}-\x{FE46}\x{FE47}\x{FE48}\x{FE49}-\x{FE4C}\x{FE4D}-\x{FE4F}\x{FE50}\x{FE51}\x{FE52}\x{FE54}\x{FE55}\x{FE56}-\x{FE57}\x{FE58}\x{FE59}\x{FE5A}\x{FE5B}\x{FE5C}\x{FE5D}\x{FE5E}\x{FE5F}\x{FE60}-\x{FE61}\x{FE62}\x{FE63}\x{FE64}-\x{FE66}\x{FE68}\x{FE69}\x{FE6A}\x{FE6B}\x{FE70}-\x{FE74}\x{FE75}\x{FE76}-\x{FEFC}\x{FEFD}-\x{FEFE}\x{FEFF}\x{FF01}-\x{FF02}\x{FF03}\x{FF04}\x{FF05}\x{FF06}-\x{FF07}\x{FF08}\x{FF09}\x{FF0A}\x{FF0B}\x{FF0C}\x{FF0D}\x{FF0E}-\x{FF0F}\x{FF1A}\x{FF1B}\x{FF1C}-\x{FF1E}\x{FF1F}-\x{FF20}\x{FF3B}\x{FF3C}\x{FF3D}\x{FF3E}\x{FF3F}\x{FF40}\x{FF5B}\x{FF5C}\x{FF5D}\x{FF5E}\x{FF5F}\x{FF60}\x{FF61}\x{FF62}\x{FF63}\x{FF64}-\x{FF65}\x{FFE0}-\x{FFE1}\x{FFE2}\x{FFE3}\x{FFE4}\x{FFE5}-\x{FFE6}\x{FFE8}\x{FFE9}-\x{FFEC}\x{FFED}-\x{FFEE}\x{FFF0}-\x{FFF8}\x{FFF9}-\x{FFFB}\x{FFFC}-\x{FFFD}\x{FFFE}-\x{FFFF}\x{10101}\x{10140}-\x{10174}\x{10175}-\x{10178}\x{10179}-\x{10189}\x{1018A}-\x{1018B}\x{1018C}\x{10190}-\x{1019C}\x{101A0}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10800}-\x{10805}\x{10806}-\x{10807}\x{10808}\x{10809}\x{1080A}-\x{10835}\x{10836}\x{10837}-\x{10838}\x{10839}-\x{1083B}\x{1083C}\x{1083D}-\x{1083E}\x{1083F}-\x{10855}\x{10856}\x{10857}\x{10858}-\x{1085F}\x{10860}-\x{10876}\x{10877}-\x{10878}\x{10879}-\x{1087F}\x{10880}-\x{1089E}\x{1089F}-\x{108A6}\x{108A7}-\x{108AF}\x{108B0}-\x{108DF}\x{108E0}-\x{108F2}\x{108F3}\x{108F4}-\x{108F5}\x{108F6}-\x{108FA}\x{108FB}-\x{108FF}\x{10900}-\x{10915}\x{10916}-\x{1091B}\x{1091C}-\x{1091E}\x{1091F}\x{10920}-\x{10939}\x{1093A}-\x{1093E}\x{1093F}\x{10940}-\x{1097F}\x{10980}-\x{109B7}\x{109B8}-\x{109BB}\x{109BC}-\x{109BD}\x{109BE}-\x{109BF}\x{109C0}-\x{109CF}\x{109D0}-\x{109D1}\x{109D2}-\x{109FF}\x{10A00}\x{10A01}-\x{10A03}\x{10A04}\x{10A05}-\x{10A06}\x{10A07}-\x{10A0B}\x{10A0C}-\x{10A0F}\x{10A10}-\x{10A13}\x{10A14}\x{10A15}-\x{10A17}\x{10A18}\x{10A19}-\x{10A35}\x{10A36}-\x{10A37}\x{10A38}-\x{10A3A}\x{10A3B}-\x{10A3E}\x{10A3F}\x{10A40}-\x{10A48}\x{10A49}-\x{10A4F}\x{10A50}-\x{10A58}\x{10A59}-\x{10A5F}\x{10A60}-\x{10A7C}\x{10A7D}-\x{10A7E}\x{10A7F}\x{10A80}-\x{10A9C}\x{10A9D}-\x{10A9F}\x{10AA0}-\x{10ABF}\x{10AC0}-\x{10AC7}\x{10AC8}\x{10AC9}-\x{10AE4}\x{10AE5}-\x{10AE6}\x{10AE7}-\x{10AEA}\x{10AEB}-\x{10AEF}\x{10AF0}-\x{10AF6}\x{10AF7}-\x{10AFF}\x{10B00}-\x{10B35}\x{10B36}-\x{10B38}\x{10B39}-\x{10B3F}\x{10B40}-\x{10B55}\x{10B56}-\x{10B57}\x{10B58}-\x{10B5F}\x{10B60}-\x{10B72}\x{10B73}-\x{10B77}\x{10B78}-\x{10B7F}\x{10B80}-\x{10B91}\x{10B92}-\x{10B98}\x{10B99}-\x{10B9C}\x{10B9D}-\x{10BA8}\x{10BA9}-\x{10BAF}\x{10BB0}-\x{10BFF}\x{10C00}-\x{10C48}\x{10C49}-\x{10C7F}\x{10C80}-\x{10CB2}\x{10CB3}-\x{10CBF}\x{10CC0}-\x{10CF2}\x{10CF3}-\x{10CF9}\x{10CFA}-\x{10CFF}\x{10D00}-\x{10D23}\x{10D24}-\x{10D27}\x{10D28}-\x{10D2F}\x{10D30}-\x{10D39}\x{10D3A}-\x{10D3F}\x{10D40}-\x{10E5F}\x{10E60}-\x{10E7E}\x{10E7F}\x{10E80}-\x{10EA9}\x{10EAA}\x{10EAB}-\x{10EAC}\x{10EAD}\x{10EAE}-\x{10EAF}\x{10EB0}-\x{10EB1}\x{10EB2}-\x{10EFF}\x{10F00}-\x{10F1C}\x{10F1D}-\x{10F26}\x{10F27}\x{10F28}-\x{10F2F}\x{10F30}-\x{10F45}\x{10F46}-\x{10F50}\x{10F51}-\x{10F54}\x{10F55}-\x{10F59}\x{10F5A}-\x{10F6F}\x{10F70}-\x{10FAF}\x{10FB0}-\x{10FC4}\x{10FC5}-\x{10FCB}\x{10FCC}-\x{10FDF}\x{10FE0}-\x{10FF6}\x{10FF7}-\x{10FFF}\x{11001}\x{11038}-\x{11046}\x{11052}-\x{11065}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{11660}-\x{1166C}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{11FD5}-\x{11FDC}\x{11FDD}-\x{11FE0}\x{11FE1}-\x{11FF1}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE2}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D200}-\x{1D241}\x{1D242}-\x{1D244}\x{1D245}\x{1D300}-\x{1D356}\x{1D6DB}\x{1D715}\x{1D74F}\x{1D789}\x{1D7C3}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E2FF}\x{1E800}-\x{1E8C4}\x{1E8C5}-\x{1E8C6}\x{1E8C7}-\x{1E8CF}\x{1E8D0}-\x{1E8D6}\x{1E8D7}-\x{1E8FF}\x{1E900}-\x{1E943}\x{1E944}-\x{1E94A}\x{1E94B}\x{1E94C}-\x{1E94F}\x{1E950}-\x{1E959}\x{1E95A}-\x{1E95D}\x{1E95E}-\x{1E95F}\x{1E960}-\x{1EC6F}\x{1EC70}\x{1EC71}-\x{1ECAB}\x{1ECAC}\x{1ECAD}-\x{1ECAF}\x{1ECB0}\x{1ECB1}-\x{1ECB4}\x{1ECB5}-\x{1ECBF}\x{1ECC0}-\x{1ECFF}\x{1ED00}\x{1ED01}-\x{1ED2D}\x{1ED2E}\x{1ED2F}-\x{1ED3D}\x{1ED3E}-\x{1ED4F}\x{1ED50}-\x{1EDFF}\x{1EE00}-\x{1EE03}\x{1EE04}\x{1EE05}-\x{1EE1F}\x{1EE20}\x{1EE21}-\x{1EE22}\x{1EE23}\x{1EE24}\x{1EE25}-\x{1EE26}\x{1EE27}\x{1EE28}\x{1EE29}-\x{1EE32}\x{1EE33}\x{1EE34}-\x{1EE37}\x{1EE38}\x{1EE39}\x{1EE3A}\x{1EE3B}\x{1EE3C}-\x{1EE41}\x{1EE42}\x{1EE43}-\x{1EE46}\x{1EE47}\x{1EE48}\x{1EE49}\x{1EE4A}\x{1EE4B}\x{1EE4C}\x{1EE4D}-\x{1EE4F}\x{1EE50}\x{1EE51}-\x{1EE52}\x{1EE53}\x{1EE54}\x{1EE55}-\x{1EE56}\x{1EE57}\x{1EE58}\x{1EE59}\x{1EE5A}\x{1EE5B}\x{1EE5C}\x{1EE5D}\x{1EE5E}\x{1EE5F}\x{1EE60}\x{1EE61}-\x{1EE62}\x{1EE63}\x{1EE64}\x{1EE65}-\x{1EE66}\x{1EE67}-\x{1EE6A}\x{1EE6B}\x{1EE6C}-\x{1EE72}\x{1EE73}\x{1EE74}-\x{1EE77}\x{1EE78}\x{1EE79}-\x{1EE7C}\x{1EE7D}\x{1EE7E}\x{1EE7F}\x{1EE80}-\x{1EE89}\x{1EE8A}\x{1EE8B}-\x{1EE9B}\x{1EE9C}-\x{1EEA0}\x{1EEA1}-\x{1EEA3}\x{1EEA4}\x{1EEA5}-\x{1EEA9}\x{1EEAA}\x{1EEAB}-\x{1EEBB}\x{1EEBC}-\x{1EEEF}\x{1EEF0}-\x{1EEF1}\x{1EEF2}-\x{1EEFF}\x{1EF00}-\x{1EFFF}\x{1F000}-\x{1F02B}\x{1F030}-\x{1F093}\x{1F0A0}-\x{1F0AE}\x{1F0B1}-\x{1F0BF}\x{1F0C1}-\x{1F0CF}\x{1F0D1}-\x{1F0F5}\x{1F10B}-\x{1F10C}\x{1F10D}-\x{1F10F}\x{1F12F}\x{1F16A}-\x{1F16F}\x{1F1AD}\x{1F260}-\x{1F265}\x{1F300}-\x{1F3FA}\x{1F3FB}-\x{1F3FF}\x{1F400}-\x{1F6D7}\x{1F6E0}-\x{1F6EC}\x{1F6F0}-\x{1F6FC}\x{1F700}-\x{1F773}\x{1F780}-\x{1F7D8}\x{1F7E0}-\x{1F7EB}\x{1F800}-\x{1F80B}\x{1F810}-\x{1F847}\x{1F850}-\x{1F859}\x{1F860}-\x{1F887}\x{1F890}-\x{1F8AD}\x{1F8B0}-\x{1F8B1}\x{1F900}-\x{1F978}\x{1F97A}-\x{1F9CB}\x{1F9CD}-\x{1FA53}\x{1FA60}-\x{1FA6D}\x{1FA70}-\x{1FA74}\x{1FA78}-\x{1FA7A}\x{1FA80}-\x{1FA86}\x{1FA90}-\x{1FAA8}\x{1FAB0}-\x{1FAB6}\x{1FAC0}-\x{1FAC2}\x{1FAD0}-\x{1FAD6}\x{1FB00}-\x{1FB92}\x{1FB94}-\x{1FBCA}\x{1FFFE}-\x{1FFFF}\x{2FFFE}-\x{2FFFF}\x{3FFFE}-\x{3FFFF}\x{4FFFE}-\x{4FFFF}\x{5FFFE}-\x{5FFFF}\x{6FFFE}-\x{6FFFF}\x{7FFFE}-\x{7FFFF}\x{8FFFE}-\x{8FFFF}\x{9FFFE}-\x{9FFFF}\x{AFFFE}-\x{AFFFF}\x{BFFFE}-\x{BFFFF}\x{CFFFE}-\x{CFFFF}\x{DFFFE}-\x{E0000}\x{E0001}\x{E0002}-\x{E001F}\x{E0020}-\x{E007F}\x{E0080}-\x{E00FF}\x{E0100}-\x{E01EF}\x{E01F0}-\x{E0FFF}\x{EFFFE}-\x{EFFFF}\x{FFFFE}-\x{FFFFF}\x{10FFFE}-\x{10FFFF}][\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A06}\x{11A09}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1D167}-\x{1D169}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{E0100}-\x{E01EF}]*$/u';
+
+ const ZWNJ = '/([\x{A872}\x{10ACD}\x{10AD7}\x{10D00}\x{10FCB}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}][\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*\x{200C}[\x{00AD}\x{0300}-\x{036F}\x{0483}-\x{0487}\x{0488}-\x{0489}\x{0591}-\x{05BD}\x{05BF}\x{05C1}-\x{05C2}\x{05C4}-\x{05C5}\x{05C7}\x{0610}-\x{061A}\x{061C}\x{064B}-\x{065F}\x{0670}\x{06D6}-\x{06DC}\x{06DF}-\x{06E4}\x{06E7}-\x{06E8}\x{06EA}-\x{06ED}\x{070F}\x{0711}\x{0730}-\x{074A}\x{07A6}-\x{07B0}\x{07EB}-\x{07F3}\x{07FD}\x{0816}-\x{0819}\x{081B}-\x{0823}\x{0825}-\x{0827}\x{0829}-\x{082D}\x{0859}-\x{085B}\x{08D3}-\x{08E1}\x{08E3}-\x{0902}\x{093A}\x{093C}\x{0941}-\x{0948}\x{094D}\x{0951}-\x{0957}\x{0962}-\x{0963}\x{0981}\x{09BC}\x{09C1}-\x{09C4}\x{09CD}\x{09E2}-\x{09E3}\x{09FE}\x{0A01}-\x{0A02}\x{0A3C}\x{0A41}-\x{0A42}\x{0A47}-\x{0A48}\x{0A4B}-\x{0A4D}\x{0A51}\x{0A70}-\x{0A71}\x{0A75}\x{0A81}-\x{0A82}\x{0ABC}\x{0AC1}-\x{0AC5}\x{0AC7}-\x{0AC8}\x{0ACD}\x{0AE2}-\x{0AE3}\x{0AFA}-\x{0AFF}\x{0B01}\x{0B3C}\x{0B3F}\x{0B41}-\x{0B44}\x{0B4D}\x{0B55}-\x{0B56}\x{0B62}-\x{0B63}\x{0B82}\x{0BC0}\x{0BCD}\x{0C00}\x{0C04}\x{0C3E}-\x{0C40}\x{0C46}-\x{0C48}\x{0C4A}-\x{0C4D}\x{0C55}-\x{0C56}\x{0C62}-\x{0C63}\x{0C81}\x{0CBC}\x{0CBF}\x{0CC6}\x{0CCC}-\x{0CCD}\x{0CE2}-\x{0CE3}\x{0D00}-\x{0D01}\x{0D3B}-\x{0D3C}\x{0D41}-\x{0D44}\x{0D4D}\x{0D62}-\x{0D63}\x{0D81}\x{0DCA}\x{0DD2}-\x{0DD4}\x{0DD6}\x{0E31}\x{0E34}-\x{0E3A}\x{0E47}-\x{0E4E}\x{0EB1}\x{0EB4}-\x{0EBC}\x{0EC8}-\x{0ECD}\x{0F18}-\x{0F19}\x{0F35}\x{0F37}\x{0F39}\x{0F71}-\x{0F7E}\x{0F80}-\x{0F84}\x{0F86}-\x{0F87}\x{0F8D}-\x{0F97}\x{0F99}-\x{0FBC}\x{0FC6}\x{102D}-\x{1030}\x{1032}-\x{1037}\x{1039}-\x{103A}\x{103D}-\x{103E}\x{1058}-\x{1059}\x{105E}-\x{1060}\x{1071}-\x{1074}\x{1082}\x{1085}-\x{1086}\x{108D}\x{109D}\x{135D}-\x{135F}\x{1712}-\x{1714}\x{1732}-\x{1734}\x{1752}-\x{1753}\x{1772}-\x{1773}\x{17B4}-\x{17B5}\x{17B7}-\x{17BD}\x{17C6}\x{17C9}-\x{17D3}\x{17DD}\x{180B}-\x{180D}\x{1885}-\x{1886}\x{18A9}\x{1920}-\x{1922}\x{1927}-\x{1928}\x{1932}\x{1939}-\x{193B}\x{1A17}-\x{1A18}\x{1A1B}\x{1A56}\x{1A58}-\x{1A5E}\x{1A60}\x{1A62}\x{1A65}-\x{1A6C}\x{1A73}-\x{1A7C}\x{1A7F}\x{1AB0}-\x{1ABD}\x{1ABE}\x{1ABF}-\x{1AC0}\x{1B00}-\x{1B03}\x{1B34}\x{1B36}-\x{1B3A}\x{1B3C}\x{1B42}\x{1B6B}-\x{1B73}\x{1B80}-\x{1B81}\x{1BA2}-\x{1BA5}\x{1BA8}-\x{1BA9}\x{1BAB}-\x{1BAD}\x{1BE6}\x{1BE8}-\x{1BE9}\x{1BED}\x{1BEF}-\x{1BF1}\x{1C2C}-\x{1C33}\x{1C36}-\x{1C37}\x{1CD0}-\x{1CD2}\x{1CD4}-\x{1CE0}\x{1CE2}-\x{1CE8}\x{1CED}\x{1CF4}\x{1CF8}-\x{1CF9}\x{1DC0}-\x{1DF9}\x{1DFB}-\x{1DFF}\x{200B}\x{200E}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{206A}-\x{206F}\x{20D0}-\x{20DC}\x{20DD}-\x{20E0}\x{20E1}\x{20E2}-\x{20E4}\x{20E5}-\x{20F0}\x{2CEF}-\x{2CF1}\x{2D7F}\x{2DE0}-\x{2DFF}\x{302A}-\x{302D}\x{3099}-\x{309A}\x{A66F}\x{A670}-\x{A672}\x{A674}-\x{A67D}\x{A69E}-\x{A69F}\x{A6F0}-\x{A6F1}\x{A802}\x{A806}\x{A80B}\x{A825}-\x{A826}\x{A82C}\x{A8C4}-\x{A8C5}\x{A8E0}-\x{A8F1}\x{A8FF}\x{A926}-\x{A92D}\x{A947}-\x{A951}\x{A980}-\x{A982}\x{A9B3}\x{A9B6}-\x{A9B9}\x{A9BC}-\x{A9BD}\x{A9E5}\x{AA29}-\x{AA2E}\x{AA31}-\x{AA32}\x{AA35}-\x{AA36}\x{AA43}\x{AA4C}\x{AA7C}\x{AAB0}\x{AAB2}-\x{AAB4}\x{AAB7}-\x{AAB8}\x{AABE}-\x{AABF}\x{AAC1}\x{AAEC}-\x{AAED}\x{AAF6}\x{ABE5}\x{ABE8}\x{ABED}\x{FB1E}\x{FE00}-\x{FE0F}\x{FE20}-\x{FE2F}\x{FEFF}\x{FFF9}-\x{FFFB}\x{101FD}\x{102E0}\x{10376}-\x{1037A}\x{10A01}-\x{10A03}\x{10A05}-\x{10A06}\x{10A0C}-\x{10A0F}\x{10A38}-\x{10A3A}\x{10A3F}\x{10AE5}-\x{10AE6}\x{10D24}-\x{10D27}\x{10EAB}-\x{10EAC}\x{10F46}-\x{10F50}\x{11001}\x{11038}-\x{11046}\x{1107F}-\x{11081}\x{110B3}-\x{110B6}\x{110B9}-\x{110BA}\x{11100}-\x{11102}\x{11127}-\x{1112B}\x{1112D}-\x{11134}\x{11173}\x{11180}-\x{11181}\x{111B6}-\x{111BE}\x{111C9}-\x{111CC}\x{111CF}\x{1122F}-\x{11231}\x{11234}\x{11236}-\x{11237}\x{1123E}\x{112DF}\x{112E3}-\x{112EA}\x{11300}-\x{11301}\x{1133B}-\x{1133C}\x{11340}\x{11366}-\x{1136C}\x{11370}-\x{11374}\x{11438}-\x{1143F}\x{11442}-\x{11444}\x{11446}\x{1145E}\x{114B3}-\x{114B8}\x{114BA}\x{114BF}-\x{114C0}\x{114C2}-\x{114C3}\x{115B2}-\x{115B5}\x{115BC}-\x{115BD}\x{115BF}-\x{115C0}\x{115DC}-\x{115DD}\x{11633}-\x{1163A}\x{1163D}\x{1163F}-\x{11640}\x{116AB}\x{116AD}\x{116B0}-\x{116B5}\x{116B7}\x{1171D}-\x{1171F}\x{11722}-\x{11725}\x{11727}-\x{1172B}\x{1182F}-\x{11837}\x{11839}-\x{1183A}\x{1193B}-\x{1193C}\x{1193E}\x{11943}\x{119D4}-\x{119D7}\x{119DA}-\x{119DB}\x{119E0}\x{11A01}-\x{11A0A}\x{11A33}-\x{11A38}\x{11A3B}-\x{11A3E}\x{11A47}\x{11A51}-\x{11A56}\x{11A59}-\x{11A5B}\x{11A8A}-\x{11A96}\x{11A98}-\x{11A99}\x{11C30}-\x{11C36}\x{11C38}-\x{11C3D}\x{11C3F}\x{11C92}-\x{11CA7}\x{11CAA}-\x{11CB0}\x{11CB2}-\x{11CB3}\x{11CB5}-\x{11CB6}\x{11D31}-\x{11D36}\x{11D3A}\x{11D3C}-\x{11D3D}\x{11D3F}-\x{11D45}\x{11D47}\x{11D90}-\x{11D91}\x{11D95}\x{11D97}\x{11EF3}-\x{11EF4}\x{13430}-\x{13438}\x{16AF0}-\x{16AF4}\x{16B30}-\x{16B36}\x{16F4F}\x{16F8F}-\x{16F92}\x{16FE4}\x{1BC9D}-\x{1BC9E}\x{1BCA0}-\x{1BCA3}\x{1D167}-\x{1D169}\x{1D173}-\x{1D17A}\x{1D17B}-\x{1D182}\x{1D185}-\x{1D18B}\x{1D1AA}-\x{1D1AD}\x{1D242}-\x{1D244}\x{1DA00}-\x{1DA36}\x{1DA3B}-\x{1DA6C}\x{1DA75}\x{1DA84}\x{1DA9B}-\x{1DA9F}\x{1DAA1}-\x{1DAAF}\x{1E000}-\x{1E006}\x{1E008}-\x{1E018}\x{1E01B}-\x{1E021}\x{1E023}-\x{1E024}\x{1E026}-\x{1E02A}\x{1E130}-\x{1E136}\x{1E2EC}-\x{1E2EF}\x{1E8D0}-\x{1E8D6}\x{1E944}-\x{1E94A}\x{1E94B}\x{E0001}\x{E0020}-\x{E007F}\x{E0100}-\x{E01EF}]*)[\x{0622}-\x{0625}\x{0627}\x{0629}\x{062F}-\x{0632}\x{0648}\x{0671}-\x{0673}\x{0675}-\x{0677}\x{0688}-\x{0699}\x{06C0}\x{06C3}-\x{06CB}\x{06CD}\x{06CF}\x{06D2}-\x{06D3}\x{06D5}\x{06EE}-\x{06EF}\x{0710}\x{0715}-\x{0719}\x{071E}\x{0728}\x{072A}\x{072C}\x{072F}\x{074D}\x{0759}-\x{075B}\x{076B}-\x{076C}\x{0771}\x{0773}-\x{0774}\x{0778}-\x{0779}\x{0840}\x{0846}-\x{0847}\x{0849}\x{0854}\x{0856}-\x{0858}\x{0867}\x{0869}-\x{086A}\x{08AA}-\x{08AC}\x{08AE}\x{08B1}-\x{08B2}\x{08B9}\x{10AC5}\x{10AC7}\x{10AC9}-\x{10ACA}\x{10ACE}-\x{10AD2}\x{10ADD}\x{10AE1}\x{10AE4}\x{10AEF}\x{10B81}\x{10B83}-\x{10B85}\x{10B89}\x{10B8C}\x{10B8E}-\x{10B8F}\x{10B91}\x{10BA9}-\x{10BAC}\x{10D22}\x{10F33}\x{10F54}\x{10FB4}-\x{10FB6}\x{10FB9}-\x{10FBA}\x{10FBD}\x{10FC2}-\x{10FC3}\x{10FC9}\x{0620}\x{0626}\x{0628}\x{062A}-\x{062E}\x{0633}-\x{063F}\x{0641}-\x{0647}\x{0649}-\x{064A}\x{066E}-\x{066F}\x{0678}-\x{0687}\x{069A}-\x{06BF}\x{06C1}-\x{06C2}\x{06CC}\x{06CE}\x{06D0}-\x{06D1}\x{06FA}-\x{06FC}\x{06FF}\x{0712}-\x{0714}\x{071A}-\x{071D}\x{071F}-\x{0727}\x{0729}\x{072B}\x{072D}-\x{072E}\x{074E}-\x{0758}\x{075C}-\x{076A}\x{076D}-\x{0770}\x{0772}\x{0775}-\x{0777}\x{077A}-\x{077F}\x{07CA}-\x{07EA}\x{0841}-\x{0845}\x{0848}\x{084A}-\x{0853}\x{0855}\x{0860}\x{0862}-\x{0865}\x{0868}\x{08A0}-\x{08A9}\x{08AF}-\x{08B0}\x{08B3}-\x{08B4}\x{08B6}-\x{08B8}\x{08BA}-\x{08C7}\x{1807}\x{1820}-\x{1842}\x{1843}\x{1844}-\x{1878}\x{1887}-\x{18A8}\x{18AA}\x{A840}-\x{A871}\x{10AC0}-\x{10AC4}\x{10AD3}-\x{10AD6}\x{10AD8}-\x{10ADC}\x{10ADE}-\x{10AE0}\x{10AEB}-\x{10AEE}\x{10B80}\x{10B82}\x{10B86}-\x{10B88}\x{10B8A}-\x{10B8B}\x{10B8D}\x{10B90}\x{10BAD}-\x{10BAE}\x{10D01}-\x{10D21}\x{10D23}\x{10F30}-\x{10F32}\x{10F34}-\x{10F44}\x{10F51}-\x{10F53}\x{10FB0}\x{10FB2}-\x{10FB3}\x{10FB8}\x{10FBB}-\x{10FBC}\x{10FBE}-\x{10FBF}\x{10FC1}\x{10FC4}\x{10FCA}\x{1E900}-\x{1E943}]/u';
+}
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php
new file mode 100644
index 0000000..0bbd335
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php
@@ -0,0 +1,8 @@
+<?php
+
+return array (
+ 223 => 'ss',
+ 962 => 'σ',
+ 8204 => '',
+ 8205 => '',
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php
new file mode 100644
index 0000000..25a5f56
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php
@@ -0,0 +1,2638 @@
+<?php
+
+return array (
+ 888 => true,
+ 889 => true,
+ 896 => true,
+ 897 => true,
+ 898 => true,
+ 899 => true,
+ 907 => true,
+ 909 => true,
+ 930 => true,
+ 1216 => true,
+ 1328 => true,
+ 1367 => true,
+ 1368 => true,
+ 1419 => true,
+ 1420 => true,
+ 1424 => true,
+ 1480 => true,
+ 1481 => true,
+ 1482 => true,
+ 1483 => true,
+ 1484 => true,
+ 1485 => true,
+ 1486 => true,
+ 1487 => true,
+ 1515 => true,
+ 1516 => true,
+ 1517 => true,
+ 1518 => true,
+ 1525 => true,
+ 1526 => true,
+ 1527 => true,
+ 1528 => true,
+ 1529 => true,
+ 1530 => true,
+ 1531 => true,
+ 1532 => true,
+ 1533 => true,
+ 1534 => true,
+ 1535 => true,
+ 1536 => true,
+ 1537 => true,
+ 1538 => true,
+ 1539 => true,
+ 1540 => true,
+ 1541 => true,
+ 1564 => true,
+ 1565 => true,
+ 1757 => true,
+ 1806 => true,
+ 1807 => true,
+ 1867 => true,
+ 1868 => true,
+ 1970 => true,
+ 1971 => true,
+ 1972 => true,
+ 1973 => true,
+ 1974 => true,
+ 1975 => true,
+ 1976 => true,
+ 1977 => true,
+ 1978 => true,
+ 1979 => true,
+ 1980 => true,
+ 1981 => true,
+ 1982 => true,
+ 1983 => true,
+ 2043 => true,
+ 2044 => true,
+ 2094 => true,
+ 2095 => true,
+ 2111 => true,
+ 2140 => true,
+ 2141 => true,
+ 2143 => true,
+ 2229 => true,
+ 2248 => true,
+ 2249 => true,
+ 2250 => true,
+ 2251 => true,
+ 2252 => true,
+ 2253 => true,
+ 2254 => true,
+ 2255 => true,
+ 2256 => true,
+ 2257 => true,
+ 2258 => true,
+ 2274 => true,
+ 2436 => true,
+ 2445 => true,
+ 2446 => true,
+ 2449 => true,
+ 2450 => true,
+ 2473 => true,
+ 2481 => true,
+ 2483 => true,
+ 2484 => true,
+ 2485 => true,
+ 2490 => true,
+ 2491 => true,
+ 2501 => true,
+ 2502 => true,
+ 2505 => true,
+ 2506 => true,
+ 2511 => true,
+ 2512 => true,
+ 2513 => true,
+ 2514 => true,
+ 2515 => true,
+ 2516 => true,
+ 2517 => true,
+ 2518 => true,
+ 2520 => true,
+ 2521 => true,
+ 2522 => true,
+ 2523 => true,
+ 2526 => true,
+ 2532 => true,
+ 2533 => true,
+ 2559 => true,
+ 2560 => true,
+ 2564 => true,
+ 2571 => true,
+ 2572 => true,
+ 2573 => true,
+ 2574 => true,
+ 2577 => true,
+ 2578 => true,
+ 2601 => true,
+ 2609 => true,
+ 2612 => true,
+ 2615 => true,
+ 2618 => true,
+ 2619 => true,
+ 2621 => true,
+ 2627 => true,
+ 2628 => true,
+ 2629 => true,
+ 2630 => true,
+ 2633 => true,
+ 2634 => true,
+ 2638 => true,
+ 2639 => true,
+ 2640 => true,
+ 2642 => true,
+ 2643 => true,
+ 2644 => true,
+ 2645 => true,
+ 2646 => true,
+ 2647 => true,
+ 2648 => true,
+ 2653 => true,
+ 2655 => true,
+ 2656 => true,
+ 2657 => true,
+ 2658 => true,
+ 2659 => true,
+ 2660 => true,
+ 2661 => true,
+ 2679 => true,
+ 2680 => true,
+ 2681 => true,
+ 2682 => true,
+ 2683 => true,
+ 2684 => true,
+ 2685 => true,
+ 2686 => true,
+ 2687 => true,
+ 2688 => true,
+ 2692 => true,
+ 2702 => true,
+ 2706 => true,
+ 2729 => true,
+ 2737 => true,
+ 2740 => true,
+ 2746 => true,
+ 2747 => true,
+ 2758 => true,
+ 2762 => true,
+ 2766 => true,
+ 2767 => true,
+ 2769 => true,
+ 2770 => true,
+ 2771 => true,
+ 2772 => true,
+ 2773 => true,
+ 2774 => true,
+ 2775 => true,
+ 2776 => true,
+ 2777 => true,
+ 2778 => true,
+ 2779 => true,
+ 2780 => true,
+ 2781 => true,
+ 2782 => true,
+ 2783 => true,
+ 2788 => true,
+ 2789 => true,
+ 2802 => true,
+ 2803 => true,
+ 2804 => true,
+ 2805 => true,
+ 2806 => true,
+ 2807 => true,
+ 2808 => true,
+ 2816 => true,
+ 2820 => true,
+ 2829 => true,
+ 2830 => true,
+ 2833 => true,
+ 2834 => true,
+ 2857 => true,
+ 2865 => true,
+ 2868 => true,
+ 2874 => true,
+ 2875 => true,
+ 2885 => true,
+ 2886 => true,
+ 2889 => true,
+ 2890 => true,
+ 2894 => true,
+ 2895 => true,
+ 2896 => true,
+ 2897 => true,
+ 2898 => true,
+ 2899 => true,
+ 2900 => true,
+ 2904 => true,
+ 2905 => true,
+ 2906 => true,
+ 2907 => true,
+ 2910 => true,
+ 2916 => true,
+ 2917 => true,
+ 2936 => true,
+ 2937 => true,
+ 2938 => true,
+ 2939 => true,
+ 2940 => true,
+ 2941 => true,
+ 2942 => true,
+ 2943 => true,
+ 2944 => true,
+ 2945 => true,
+ 2948 => true,
+ 2955 => true,
+ 2956 => true,
+ 2957 => true,
+ 2961 => true,
+ 2966 => true,
+ 2967 => true,
+ 2968 => true,
+ 2971 => true,
+ 2973 => true,
+ 2976 => true,
+ 2977 => true,
+ 2978 => true,
+ 2981 => true,
+ 2982 => true,
+ 2983 => true,
+ 2987 => true,
+ 2988 => true,
+ 2989 => true,
+ 3002 => true,
+ 3003 => true,
+ 3004 => true,
+ 3005 => true,
+ 3011 => true,
+ 3012 => true,
+ 3013 => true,
+ 3017 => true,
+ 3022 => true,
+ 3023 => true,
+ 3025 => true,
+ 3026 => true,
+ 3027 => true,
+ 3028 => true,
+ 3029 => true,
+ 3030 => true,
+ 3032 => true,
+ 3033 => true,
+ 3034 => true,
+ 3035 => true,
+ 3036 => true,
+ 3037 => true,
+ 3038 => true,
+ 3039 => true,
+ 3040 => true,
+ 3041 => true,
+ 3042 => true,
+ 3043 => true,
+ 3044 => true,
+ 3045 => true,
+ 3067 => true,
+ 3068 => true,
+ 3069 => true,
+ 3070 => true,
+ 3071 => true,
+ 3085 => true,
+ 3089 => true,
+ 3113 => true,
+ 3130 => true,
+ 3131 => true,
+ 3132 => true,
+ 3141 => true,
+ 3145 => true,
+ 3150 => true,
+ 3151 => true,
+ 3152 => true,
+ 3153 => true,
+ 3154 => true,
+ 3155 => true,
+ 3156 => true,
+ 3159 => true,
+ 3163 => true,
+ 3164 => true,
+ 3165 => true,
+ 3166 => true,
+ 3167 => true,
+ 3172 => true,
+ 3173 => true,
+ 3184 => true,
+ 3185 => true,
+ 3186 => true,
+ 3187 => true,
+ 3188 => true,
+ 3189 => true,
+ 3190 => true,
+ 3213 => true,
+ 3217 => true,
+ 3241 => true,
+ 3252 => true,
+ 3258 => true,
+ 3259 => true,
+ 3269 => true,
+ 3273 => true,
+ 3278 => true,
+ 3279 => true,
+ 3280 => true,
+ 3281 => true,
+ 3282 => true,
+ 3283 => true,
+ 3284 => true,
+ 3287 => true,
+ 3288 => true,
+ 3289 => true,
+ 3290 => true,
+ 3291 => true,
+ 3292 => true,
+ 3293 => true,
+ 3295 => true,
+ 3300 => true,
+ 3301 => true,
+ 3312 => true,
+ 3315 => true,
+ 3316 => true,
+ 3317 => true,
+ 3318 => true,
+ 3319 => true,
+ 3320 => true,
+ 3321 => true,
+ 3322 => true,
+ 3323 => true,
+ 3324 => true,
+ 3325 => true,
+ 3326 => true,
+ 3327 => true,
+ 3341 => true,
+ 3345 => true,
+ 3397 => true,
+ 3401 => true,
+ 3408 => true,
+ 3409 => true,
+ 3410 => true,
+ 3411 => true,
+ 3428 => true,
+ 3429 => true,
+ 3456 => true,
+ 3460 => true,
+ 3479 => true,
+ 3480 => true,
+ 3481 => true,
+ 3506 => true,
+ 3516 => true,
+ 3518 => true,
+ 3519 => true,
+ 3527 => true,
+ 3528 => true,
+ 3529 => true,
+ 3531 => true,
+ 3532 => true,
+ 3533 => true,
+ 3534 => true,
+ 3541 => true,
+ 3543 => true,
+ 3552 => true,
+ 3553 => true,
+ 3554 => true,
+ 3555 => true,
+ 3556 => true,
+ 3557 => true,
+ 3568 => true,
+ 3569 => true,
+ 3573 => true,
+ 3574 => true,
+ 3575 => true,
+ 3576 => true,
+ 3577 => true,
+ 3578 => true,
+ 3579 => true,
+ 3580 => true,
+ 3581 => true,
+ 3582 => true,
+ 3583 => true,
+ 3584 => true,
+ 3643 => true,
+ 3644 => true,
+ 3645 => true,
+ 3646 => true,
+ 3715 => true,
+ 3717 => true,
+ 3723 => true,
+ 3748 => true,
+ 3750 => true,
+ 3774 => true,
+ 3775 => true,
+ 3781 => true,
+ 3783 => true,
+ 3790 => true,
+ 3791 => true,
+ 3802 => true,
+ 3803 => true,
+ 3912 => true,
+ 3949 => true,
+ 3950 => true,
+ 3951 => true,
+ 3952 => true,
+ 3992 => true,
+ 4029 => true,
+ 4045 => true,
+ 4294 => true,
+ 4296 => true,
+ 4297 => true,
+ 4298 => true,
+ 4299 => true,
+ 4300 => true,
+ 4302 => true,
+ 4303 => true,
+ 4447 => true,
+ 4448 => true,
+ 4681 => true,
+ 4686 => true,
+ 4687 => true,
+ 4695 => true,
+ 4697 => true,
+ 4702 => true,
+ 4703 => true,
+ 4745 => true,
+ 4750 => true,
+ 4751 => true,
+ 4785 => true,
+ 4790 => true,
+ 4791 => true,
+ 4799 => true,
+ 4801 => true,
+ 4806 => true,
+ 4807 => true,
+ 4823 => true,
+ 4881 => true,
+ 4886 => true,
+ 4887 => true,
+ 4955 => true,
+ 4956 => true,
+ 4989 => true,
+ 4990 => true,
+ 4991 => true,
+ 5018 => true,
+ 5019 => true,
+ 5020 => true,
+ 5021 => true,
+ 5022 => true,
+ 5023 => true,
+ 5110 => true,
+ 5111 => true,
+ 5118 => true,
+ 5119 => true,
+ 5760 => true,
+ 5789 => true,
+ 5790 => true,
+ 5791 => true,
+ 5881 => true,
+ 5882 => true,
+ 5883 => true,
+ 5884 => true,
+ 5885 => true,
+ 5886 => true,
+ 5887 => true,
+ 5901 => true,
+ 5909 => true,
+ 5910 => true,
+ 5911 => true,
+ 5912 => true,
+ 5913 => true,
+ 5914 => true,
+ 5915 => true,
+ 5916 => true,
+ 5917 => true,
+ 5918 => true,
+ 5919 => true,
+ 5943 => true,
+ 5944 => true,
+ 5945 => true,
+ 5946 => true,
+ 5947 => true,
+ 5948 => true,
+ 5949 => true,
+ 5950 => true,
+ 5951 => true,
+ 5972 => true,
+ 5973 => true,
+ 5974 => true,
+ 5975 => true,
+ 5976 => true,
+ 5977 => true,
+ 5978 => true,
+ 5979 => true,
+ 5980 => true,
+ 5981 => true,
+ 5982 => true,
+ 5983 => true,
+ 5997 => true,
+ 6001 => true,
+ 6004 => true,
+ 6005 => true,
+ 6006 => true,
+ 6007 => true,
+ 6008 => true,
+ 6009 => true,
+ 6010 => true,
+ 6011 => true,
+ 6012 => true,
+ 6013 => true,
+ 6014 => true,
+ 6015 => true,
+ 6068 => true,
+ 6069 => true,
+ 6110 => true,
+ 6111 => true,
+ 6122 => true,
+ 6123 => true,
+ 6124 => true,
+ 6125 => true,
+ 6126 => true,
+ 6127 => true,
+ 6138 => true,
+ 6139 => true,
+ 6140 => true,
+ 6141 => true,
+ 6142 => true,
+ 6143 => true,
+ 6150 => true,
+ 6158 => true,
+ 6159 => true,
+ 6170 => true,
+ 6171 => true,
+ 6172 => true,
+ 6173 => true,
+ 6174 => true,
+ 6175 => true,
+ 6265 => true,
+ 6266 => true,
+ 6267 => true,
+ 6268 => true,
+ 6269 => true,
+ 6270 => true,
+ 6271 => true,
+ 6315 => true,
+ 6316 => true,
+ 6317 => true,
+ 6318 => true,
+ 6319 => true,
+ 6390 => true,
+ 6391 => true,
+ 6392 => true,
+ 6393 => true,
+ 6394 => true,
+ 6395 => true,
+ 6396 => true,
+ 6397 => true,
+ 6398 => true,
+ 6399 => true,
+ 6431 => true,
+ 6444 => true,
+ 6445 => true,
+ 6446 => true,
+ 6447 => true,
+ 6460 => true,
+ 6461 => true,
+ 6462 => true,
+ 6463 => true,
+ 6465 => true,
+ 6466 => true,
+ 6467 => true,
+ 6510 => true,
+ 6511 => true,
+ 6517 => true,
+ 6518 => true,
+ 6519 => true,
+ 6520 => true,
+ 6521 => true,
+ 6522 => true,
+ 6523 => true,
+ 6524 => true,
+ 6525 => true,
+ 6526 => true,
+ 6527 => true,
+ 6572 => true,
+ 6573 => true,
+ 6574 => true,
+ 6575 => true,
+ 6602 => true,
+ 6603 => true,
+ 6604 => true,
+ 6605 => true,
+ 6606 => true,
+ 6607 => true,
+ 6619 => true,
+ 6620 => true,
+ 6621 => true,
+ 6684 => true,
+ 6685 => true,
+ 6751 => true,
+ 6781 => true,
+ 6782 => true,
+ 6794 => true,
+ 6795 => true,
+ 6796 => true,
+ 6797 => true,
+ 6798 => true,
+ 6799 => true,
+ 6810 => true,
+ 6811 => true,
+ 6812 => true,
+ 6813 => true,
+ 6814 => true,
+ 6815 => true,
+ 6830 => true,
+ 6831 => true,
+ 6988 => true,
+ 6989 => true,
+ 6990 => true,
+ 6991 => true,
+ 7037 => true,
+ 7038 => true,
+ 7039 => true,
+ 7156 => true,
+ 7157 => true,
+ 7158 => true,
+ 7159 => true,
+ 7160 => true,
+ 7161 => true,
+ 7162 => true,
+ 7163 => true,
+ 7224 => true,
+ 7225 => true,
+ 7226 => true,
+ 7242 => true,
+ 7243 => true,
+ 7244 => true,
+ 7305 => true,
+ 7306 => true,
+ 7307 => true,
+ 7308 => true,
+ 7309 => true,
+ 7310 => true,
+ 7311 => true,
+ 7355 => true,
+ 7356 => true,
+ 7368 => true,
+ 7369 => true,
+ 7370 => true,
+ 7371 => true,
+ 7372 => true,
+ 7373 => true,
+ 7374 => true,
+ 7375 => true,
+ 7419 => true,
+ 7420 => true,
+ 7421 => true,
+ 7422 => true,
+ 7423 => true,
+ 7674 => true,
+ 7958 => true,
+ 7959 => true,
+ 7966 => true,
+ 7967 => true,
+ 8006 => true,
+ 8007 => true,
+ 8014 => true,
+ 8015 => true,
+ 8024 => true,
+ 8026 => true,
+ 8028 => true,
+ 8030 => true,
+ 8062 => true,
+ 8063 => true,
+ 8117 => true,
+ 8133 => true,
+ 8148 => true,
+ 8149 => true,
+ 8156 => true,
+ 8176 => true,
+ 8177 => true,
+ 8181 => true,
+ 8191 => true,
+ 8206 => true,
+ 8207 => true,
+ 8228 => true,
+ 8229 => true,
+ 8230 => true,
+ 8232 => true,
+ 8233 => true,
+ 8234 => true,
+ 8235 => true,
+ 8236 => true,
+ 8237 => true,
+ 8238 => true,
+ 8289 => true,
+ 8290 => true,
+ 8291 => true,
+ 8293 => true,
+ 8294 => true,
+ 8295 => true,
+ 8296 => true,
+ 8297 => true,
+ 8298 => true,
+ 8299 => true,
+ 8300 => true,
+ 8301 => true,
+ 8302 => true,
+ 8303 => true,
+ 8306 => true,
+ 8307 => true,
+ 8335 => true,
+ 8349 => true,
+ 8350 => true,
+ 8351 => true,
+ 8384 => true,
+ 8385 => true,
+ 8386 => true,
+ 8387 => true,
+ 8388 => true,
+ 8389 => true,
+ 8390 => true,
+ 8391 => true,
+ 8392 => true,
+ 8393 => true,
+ 8394 => true,
+ 8395 => true,
+ 8396 => true,
+ 8397 => true,
+ 8398 => true,
+ 8399 => true,
+ 8433 => true,
+ 8434 => true,
+ 8435 => true,
+ 8436 => true,
+ 8437 => true,
+ 8438 => true,
+ 8439 => true,
+ 8440 => true,
+ 8441 => true,
+ 8442 => true,
+ 8443 => true,
+ 8444 => true,
+ 8445 => true,
+ 8446 => true,
+ 8447 => true,
+ 8498 => true,
+ 8579 => true,
+ 8588 => true,
+ 8589 => true,
+ 8590 => true,
+ 8591 => true,
+ 9255 => true,
+ 9256 => true,
+ 9257 => true,
+ 9258 => true,
+ 9259 => true,
+ 9260 => true,
+ 9261 => true,
+ 9262 => true,
+ 9263 => true,
+ 9264 => true,
+ 9265 => true,
+ 9266 => true,
+ 9267 => true,
+ 9268 => true,
+ 9269 => true,
+ 9270 => true,
+ 9271 => true,
+ 9272 => true,
+ 9273 => true,
+ 9274 => true,
+ 9275 => true,
+ 9276 => true,
+ 9277 => true,
+ 9278 => true,
+ 9279 => true,
+ 9291 => true,
+ 9292 => true,
+ 9293 => true,
+ 9294 => true,
+ 9295 => true,
+ 9296 => true,
+ 9297 => true,
+ 9298 => true,
+ 9299 => true,
+ 9300 => true,
+ 9301 => true,
+ 9302 => true,
+ 9303 => true,
+ 9304 => true,
+ 9305 => true,
+ 9306 => true,
+ 9307 => true,
+ 9308 => true,
+ 9309 => true,
+ 9310 => true,
+ 9311 => true,
+ 9352 => true,
+ 9353 => true,
+ 9354 => true,
+ 9355 => true,
+ 9356 => true,
+ 9357 => true,
+ 9358 => true,
+ 9359 => true,
+ 9360 => true,
+ 9361 => true,
+ 9362 => true,
+ 9363 => true,
+ 9364 => true,
+ 9365 => true,
+ 9366 => true,
+ 9367 => true,
+ 9368 => true,
+ 9369 => true,
+ 9370 => true,
+ 9371 => true,
+ 11124 => true,
+ 11125 => true,
+ 11158 => true,
+ 11311 => true,
+ 11359 => true,
+ 11508 => true,
+ 11509 => true,
+ 11510 => true,
+ 11511 => true,
+ 11512 => true,
+ 11558 => true,
+ 11560 => true,
+ 11561 => true,
+ 11562 => true,
+ 11563 => true,
+ 11564 => true,
+ 11566 => true,
+ 11567 => true,
+ 11624 => true,
+ 11625 => true,
+ 11626 => true,
+ 11627 => true,
+ 11628 => true,
+ 11629 => true,
+ 11630 => true,
+ 11633 => true,
+ 11634 => true,
+ 11635 => true,
+ 11636 => true,
+ 11637 => true,
+ 11638 => true,
+ 11639 => true,
+ 11640 => true,
+ 11641 => true,
+ 11642 => true,
+ 11643 => true,
+ 11644 => true,
+ 11645 => true,
+ 11646 => true,
+ 11671 => true,
+ 11672 => true,
+ 11673 => true,
+ 11674 => true,
+ 11675 => true,
+ 11676 => true,
+ 11677 => true,
+ 11678 => true,
+ 11679 => true,
+ 11687 => true,
+ 11695 => true,
+ 11703 => true,
+ 11711 => true,
+ 11719 => true,
+ 11727 => true,
+ 11735 => true,
+ 11743 => true,
+ 11930 => true,
+ 12020 => true,
+ 12021 => true,
+ 12022 => true,
+ 12023 => true,
+ 12024 => true,
+ 12025 => true,
+ 12026 => true,
+ 12027 => true,
+ 12028 => true,
+ 12029 => true,
+ 12030 => true,
+ 12031 => true,
+ 12246 => true,
+ 12247 => true,
+ 12248 => true,
+ 12249 => true,
+ 12250 => true,
+ 12251 => true,
+ 12252 => true,
+ 12253 => true,
+ 12254 => true,
+ 12255 => true,
+ 12256 => true,
+ 12257 => true,
+ 12258 => true,
+ 12259 => true,
+ 12260 => true,
+ 12261 => true,
+ 12262 => true,
+ 12263 => true,
+ 12264 => true,
+ 12265 => true,
+ 12266 => true,
+ 12267 => true,
+ 12268 => true,
+ 12269 => true,
+ 12270 => true,
+ 12271 => true,
+ 12272 => true,
+ 12273 => true,
+ 12274 => true,
+ 12275 => true,
+ 12276 => true,
+ 12277 => true,
+ 12278 => true,
+ 12279 => true,
+ 12280 => true,
+ 12281 => true,
+ 12282 => true,
+ 12283 => true,
+ 12284 => true,
+ 12285 => true,
+ 12286 => true,
+ 12287 => true,
+ 12352 => true,
+ 12439 => true,
+ 12440 => true,
+ 12544 => true,
+ 12545 => true,
+ 12546 => true,
+ 12547 => true,
+ 12548 => true,
+ 12592 => true,
+ 12644 => true,
+ 12687 => true,
+ 12772 => true,
+ 12773 => true,
+ 12774 => true,
+ 12775 => true,
+ 12776 => true,
+ 12777 => true,
+ 12778 => true,
+ 12779 => true,
+ 12780 => true,
+ 12781 => true,
+ 12782 => true,
+ 12783 => true,
+ 12831 => true,
+ 13250 => true,
+ 13255 => true,
+ 13272 => true,
+ 40957 => true,
+ 40958 => true,
+ 40959 => true,
+ 42125 => true,
+ 42126 => true,
+ 42127 => true,
+ 42183 => true,
+ 42184 => true,
+ 42185 => true,
+ 42186 => true,
+ 42187 => true,
+ 42188 => true,
+ 42189 => true,
+ 42190 => true,
+ 42191 => true,
+ 42540 => true,
+ 42541 => true,
+ 42542 => true,
+ 42543 => true,
+ 42544 => true,
+ 42545 => true,
+ 42546 => true,
+ 42547 => true,
+ 42548 => true,
+ 42549 => true,
+ 42550 => true,
+ 42551 => true,
+ 42552 => true,
+ 42553 => true,
+ 42554 => true,
+ 42555 => true,
+ 42556 => true,
+ 42557 => true,
+ 42558 => true,
+ 42559 => true,
+ 42744 => true,
+ 42745 => true,
+ 42746 => true,
+ 42747 => true,
+ 42748 => true,
+ 42749 => true,
+ 42750 => true,
+ 42751 => true,
+ 42944 => true,
+ 42945 => true,
+ 43053 => true,
+ 43054 => true,
+ 43055 => true,
+ 43066 => true,
+ 43067 => true,
+ 43068 => true,
+ 43069 => true,
+ 43070 => true,
+ 43071 => true,
+ 43128 => true,
+ 43129 => true,
+ 43130 => true,
+ 43131 => true,
+ 43132 => true,
+ 43133 => true,
+ 43134 => true,
+ 43135 => true,
+ 43206 => true,
+ 43207 => true,
+ 43208 => true,
+ 43209 => true,
+ 43210 => true,
+ 43211 => true,
+ 43212 => true,
+ 43213 => true,
+ 43226 => true,
+ 43227 => true,
+ 43228 => true,
+ 43229 => true,
+ 43230 => true,
+ 43231 => true,
+ 43348 => true,
+ 43349 => true,
+ 43350 => true,
+ 43351 => true,
+ 43352 => true,
+ 43353 => true,
+ 43354 => true,
+ 43355 => true,
+ 43356 => true,
+ 43357 => true,
+ 43358 => true,
+ 43389 => true,
+ 43390 => true,
+ 43391 => true,
+ 43470 => true,
+ 43482 => true,
+ 43483 => true,
+ 43484 => true,
+ 43485 => true,
+ 43519 => true,
+ 43575 => true,
+ 43576 => true,
+ 43577 => true,
+ 43578 => true,
+ 43579 => true,
+ 43580 => true,
+ 43581 => true,
+ 43582 => true,
+ 43583 => true,
+ 43598 => true,
+ 43599 => true,
+ 43610 => true,
+ 43611 => true,
+ 43715 => true,
+ 43716 => true,
+ 43717 => true,
+ 43718 => true,
+ 43719 => true,
+ 43720 => true,
+ 43721 => true,
+ 43722 => true,
+ 43723 => true,
+ 43724 => true,
+ 43725 => true,
+ 43726 => true,
+ 43727 => true,
+ 43728 => true,
+ 43729 => true,
+ 43730 => true,
+ 43731 => true,
+ 43732 => true,
+ 43733 => true,
+ 43734 => true,
+ 43735 => true,
+ 43736 => true,
+ 43737 => true,
+ 43738 => true,
+ 43767 => true,
+ 43768 => true,
+ 43769 => true,
+ 43770 => true,
+ 43771 => true,
+ 43772 => true,
+ 43773 => true,
+ 43774 => true,
+ 43775 => true,
+ 43776 => true,
+ 43783 => true,
+ 43784 => true,
+ 43791 => true,
+ 43792 => true,
+ 43799 => true,
+ 43800 => true,
+ 43801 => true,
+ 43802 => true,
+ 43803 => true,
+ 43804 => true,
+ 43805 => true,
+ 43806 => true,
+ 43807 => true,
+ 43815 => true,
+ 43823 => true,
+ 43884 => true,
+ 43885 => true,
+ 43886 => true,
+ 43887 => true,
+ 44014 => true,
+ 44015 => true,
+ 44026 => true,
+ 44027 => true,
+ 44028 => true,
+ 44029 => true,
+ 44030 => true,
+ 44031 => true,
+ 55204 => true,
+ 55205 => true,
+ 55206 => true,
+ 55207 => true,
+ 55208 => true,
+ 55209 => true,
+ 55210 => true,
+ 55211 => true,
+ 55212 => true,
+ 55213 => true,
+ 55214 => true,
+ 55215 => true,
+ 55239 => true,
+ 55240 => true,
+ 55241 => true,
+ 55242 => true,
+ 55292 => true,
+ 55293 => true,
+ 55294 => true,
+ 55295 => true,
+ 64110 => true,
+ 64111 => true,
+ 64263 => true,
+ 64264 => true,
+ 64265 => true,
+ 64266 => true,
+ 64267 => true,
+ 64268 => true,
+ 64269 => true,
+ 64270 => true,
+ 64271 => true,
+ 64272 => true,
+ 64273 => true,
+ 64274 => true,
+ 64280 => true,
+ 64281 => true,
+ 64282 => true,
+ 64283 => true,
+ 64284 => true,
+ 64311 => true,
+ 64317 => true,
+ 64319 => true,
+ 64322 => true,
+ 64325 => true,
+ 64450 => true,
+ 64451 => true,
+ 64452 => true,
+ 64453 => true,
+ 64454 => true,
+ 64455 => true,
+ 64456 => true,
+ 64457 => true,
+ 64458 => true,
+ 64459 => true,
+ 64460 => true,
+ 64461 => true,
+ 64462 => true,
+ 64463 => true,
+ 64464 => true,
+ 64465 => true,
+ 64466 => true,
+ 64832 => true,
+ 64833 => true,
+ 64834 => true,
+ 64835 => true,
+ 64836 => true,
+ 64837 => true,
+ 64838 => true,
+ 64839 => true,
+ 64840 => true,
+ 64841 => true,
+ 64842 => true,
+ 64843 => true,
+ 64844 => true,
+ 64845 => true,
+ 64846 => true,
+ 64847 => true,
+ 64912 => true,
+ 64913 => true,
+ 64968 => true,
+ 64969 => true,
+ 64970 => true,
+ 64971 => true,
+ 64972 => true,
+ 64973 => true,
+ 64974 => true,
+ 64975 => true,
+ 65022 => true,
+ 65023 => true,
+ 65042 => true,
+ 65049 => true,
+ 65050 => true,
+ 65051 => true,
+ 65052 => true,
+ 65053 => true,
+ 65054 => true,
+ 65055 => true,
+ 65072 => true,
+ 65106 => true,
+ 65107 => true,
+ 65127 => true,
+ 65132 => true,
+ 65133 => true,
+ 65134 => true,
+ 65135 => true,
+ 65141 => true,
+ 65277 => true,
+ 65278 => true,
+ 65280 => true,
+ 65440 => true,
+ 65471 => true,
+ 65472 => true,
+ 65473 => true,
+ 65480 => true,
+ 65481 => true,
+ 65488 => true,
+ 65489 => true,
+ 65496 => true,
+ 65497 => true,
+ 65501 => true,
+ 65502 => true,
+ 65503 => true,
+ 65511 => true,
+ 65519 => true,
+ 65520 => true,
+ 65521 => true,
+ 65522 => true,
+ 65523 => true,
+ 65524 => true,
+ 65525 => true,
+ 65526 => true,
+ 65527 => true,
+ 65528 => true,
+ 65529 => true,
+ 65530 => true,
+ 65531 => true,
+ 65532 => true,
+ 65533 => true,
+ 65534 => true,
+ 65535 => true,
+ 65548 => true,
+ 65575 => true,
+ 65595 => true,
+ 65598 => true,
+ 65614 => true,
+ 65615 => true,
+ 65787 => true,
+ 65788 => true,
+ 65789 => true,
+ 65790 => true,
+ 65791 => true,
+ 65795 => true,
+ 65796 => true,
+ 65797 => true,
+ 65798 => true,
+ 65844 => true,
+ 65845 => true,
+ 65846 => true,
+ 65935 => true,
+ 65949 => true,
+ 65950 => true,
+ 65951 => true,
+ 66205 => true,
+ 66206 => true,
+ 66207 => true,
+ 66257 => true,
+ 66258 => true,
+ 66259 => true,
+ 66260 => true,
+ 66261 => true,
+ 66262 => true,
+ 66263 => true,
+ 66264 => true,
+ 66265 => true,
+ 66266 => true,
+ 66267 => true,
+ 66268 => true,
+ 66269 => true,
+ 66270 => true,
+ 66271 => true,
+ 66300 => true,
+ 66301 => true,
+ 66302 => true,
+ 66303 => true,
+ 66340 => true,
+ 66341 => true,
+ 66342 => true,
+ 66343 => true,
+ 66344 => true,
+ 66345 => true,
+ 66346 => true,
+ 66347 => true,
+ 66348 => true,
+ 66379 => true,
+ 66380 => true,
+ 66381 => true,
+ 66382 => true,
+ 66383 => true,
+ 66427 => true,
+ 66428 => true,
+ 66429 => true,
+ 66430 => true,
+ 66431 => true,
+ 66462 => true,
+ 66500 => true,
+ 66501 => true,
+ 66502 => true,
+ 66503 => true,
+ 66718 => true,
+ 66719 => true,
+ 66730 => true,
+ 66731 => true,
+ 66732 => true,
+ 66733 => true,
+ 66734 => true,
+ 66735 => true,
+ 66772 => true,
+ 66773 => true,
+ 66774 => true,
+ 66775 => true,
+ 66812 => true,
+ 66813 => true,
+ 66814 => true,
+ 66815 => true,
+ 66856 => true,
+ 66857 => true,
+ 66858 => true,
+ 66859 => true,
+ 66860 => true,
+ 66861 => true,
+ 66862 => true,
+ 66863 => true,
+ 66916 => true,
+ 66917 => true,
+ 66918 => true,
+ 66919 => true,
+ 66920 => true,
+ 66921 => true,
+ 66922 => true,
+ 66923 => true,
+ 66924 => true,
+ 66925 => true,
+ 66926 => true,
+ 67383 => true,
+ 67384 => true,
+ 67385 => true,
+ 67386 => true,
+ 67387 => true,
+ 67388 => true,
+ 67389 => true,
+ 67390 => true,
+ 67391 => true,
+ 67414 => true,
+ 67415 => true,
+ 67416 => true,
+ 67417 => true,
+ 67418 => true,
+ 67419 => true,
+ 67420 => true,
+ 67421 => true,
+ 67422 => true,
+ 67423 => true,
+ 67590 => true,
+ 67591 => true,
+ 67593 => true,
+ 67638 => true,
+ 67641 => true,
+ 67642 => true,
+ 67643 => true,
+ 67645 => true,
+ 67646 => true,
+ 67670 => true,
+ 67743 => true,
+ 67744 => true,
+ 67745 => true,
+ 67746 => true,
+ 67747 => true,
+ 67748 => true,
+ 67749 => true,
+ 67750 => true,
+ 67827 => true,
+ 67830 => true,
+ 67831 => true,
+ 67832 => true,
+ 67833 => true,
+ 67834 => true,
+ 67868 => true,
+ 67869 => true,
+ 67870 => true,
+ 67898 => true,
+ 67899 => true,
+ 67900 => true,
+ 67901 => true,
+ 67902 => true,
+ 68024 => true,
+ 68025 => true,
+ 68026 => true,
+ 68027 => true,
+ 68048 => true,
+ 68049 => true,
+ 68100 => true,
+ 68103 => true,
+ 68104 => true,
+ 68105 => true,
+ 68106 => true,
+ 68107 => true,
+ 68116 => true,
+ 68120 => true,
+ 68150 => true,
+ 68151 => true,
+ 68155 => true,
+ 68156 => true,
+ 68157 => true,
+ 68158 => true,
+ 68169 => true,
+ 68170 => true,
+ 68171 => true,
+ 68172 => true,
+ 68173 => true,
+ 68174 => true,
+ 68175 => true,
+ 68185 => true,
+ 68186 => true,
+ 68187 => true,
+ 68188 => true,
+ 68189 => true,
+ 68190 => true,
+ 68191 => true,
+ 68327 => true,
+ 68328 => true,
+ 68329 => true,
+ 68330 => true,
+ 68343 => true,
+ 68344 => true,
+ 68345 => true,
+ 68346 => true,
+ 68347 => true,
+ 68348 => true,
+ 68349 => true,
+ 68350 => true,
+ 68351 => true,
+ 68406 => true,
+ 68407 => true,
+ 68408 => true,
+ 68438 => true,
+ 68439 => true,
+ 68467 => true,
+ 68468 => true,
+ 68469 => true,
+ 68470 => true,
+ 68471 => true,
+ 68498 => true,
+ 68499 => true,
+ 68500 => true,
+ 68501 => true,
+ 68502 => true,
+ 68503 => true,
+ 68504 => true,
+ 68509 => true,
+ 68510 => true,
+ 68511 => true,
+ 68512 => true,
+ 68513 => true,
+ 68514 => true,
+ 68515 => true,
+ 68516 => true,
+ 68517 => true,
+ 68518 => true,
+ 68519 => true,
+ 68520 => true,
+ 68787 => true,
+ 68788 => true,
+ 68789 => true,
+ 68790 => true,
+ 68791 => true,
+ 68792 => true,
+ 68793 => true,
+ 68794 => true,
+ 68795 => true,
+ 68796 => true,
+ 68797 => true,
+ 68798 => true,
+ 68799 => true,
+ 68851 => true,
+ 68852 => true,
+ 68853 => true,
+ 68854 => true,
+ 68855 => true,
+ 68856 => true,
+ 68857 => true,
+ 68904 => true,
+ 68905 => true,
+ 68906 => true,
+ 68907 => true,
+ 68908 => true,
+ 68909 => true,
+ 68910 => true,
+ 68911 => true,
+ 69247 => true,
+ 69290 => true,
+ 69294 => true,
+ 69295 => true,
+ 69416 => true,
+ 69417 => true,
+ 69418 => true,
+ 69419 => true,
+ 69420 => true,
+ 69421 => true,
+ 69422 => true,
+ 69423 => true,
+ 69580 => true,
+ 69581 => true,
+ 69582 => true,
+ 69583 => true,
+ 69584 => true,
+ 69585 => true,
+ 69586 => true,
+ 69587 => true,
+ 69588 => true,
+ 69589 => true,
+ 69590 => true,
+ 69591 => true,
+ 69592 => true,
+ 69593 => true,
+ 69594 => true,
+ 69595 => true,
+ 69596 => true,
+ 69597 => true,
+ 69598 => true,
+ 69599 => true,
+ 69623 => true,
+ 69624 => true,
+ 69625 => true,
+ 69626 => true,
+ 69627 => true,
+ 69628 => true,
+ 69629 => true,
+ 69630 => true,
+ 69631 => true,
+ 69710 => true,
+ 69711 => true,
+ 69712 => true,
+ 69713 => true,
+ 69744 => true,
+ 69745 => true,
+ 69746 => true,
+ 69747 => true,
+ 69748 => true,
+ 69749 => true,
+ 69750 => true,
+ 69751 => true,
+ 69752 => true,
+ 69753 => true,
+ 69754 => true,
+ 69755 => true,
+ 69756 => true,
+ 69757 => true,
+ 69758 => true,
+ 69821 => true,
+ 69826 => true,
+ 69827 => true,
+ 69828 => true,
+ 69829 => true,
+ 69830 => true,
+ 69831 => true,
+ 69832 => true,
+ 69833 => true,
+ 69834 => true,
+ 69835 => true,
+ 69836 => true,
+ 69837 => true,
+ 69838 => true,
+ 69839 => true,
+ 69865 => true,
+ 69866 => true,
+ 69867 => true,
+ 69868 => true,
+ 69869 => true,
+ 69870 => true,
+ 69871 => true,
+ 69882 => true,
+ 69883 => true,
+ 69884 => true,
+ 69885 => true,
+ 69886 => true,
+ 69887 => true,
+ 69941 => true,
+ 69960 => true,
+ 69961 => true,
+ 69962 => true,
+ 69963 => true,
+ 69964 => true,
+ 69965 => true,
+ 69966 => true,
+ 69967 => true,
+ 70007 => true,
+ 70008 => true,
+ 70009 => true,
+ 70010 => true,
+ 70011 => true,
+ 70012 => true,
+ 70013 => true,
+ 70014 => true,
+ 70015 => true,
+ 70112 => true,
+ 70133 => true,
+ 70134 => true,
+ 70135 => true,
+ 70136 => true,
+ 70137 => true,
+ 70138 => true,
+ 70139 => true,
+ 70140 => true,
+ 70141 => true,
+ 70142 => true,
+ 70143 => true,
+ 70162 => true,
+ 70279 => true,
+ 70281 => true,
+ 70286 => true,
+ 70302 => true,
+ 70314 => true,
+ 70315 => true,
+ 70316 => true,
+ 70317 => true,
+ 70318 => true,
+ 70319 => true,
+ 70379 => true,
+ 70380 => true,
+ 70381 => true,
+ 70382 => true,
+ 70383 => true,
+ 70394 => true,
+ 70395 => true,
+ 70396 => true,
+ 70397 => true,
+ 70398 => true,
+ 70399 => true,
+ 70404 => true,
+ 70413 => true,
+ 70414 => true,
+ 70417 => true,
+ 70418 => true,
+ 70441 => true,
+ 70449 => true,
+ 70452 => true,
+ 70458 => true,
+ 70469 => true,
+ 70470 => true,
+ 70473 => true,
+ 70474 => true,
+ 70478 => true,
+ 70479 => true,
+ 70481 => true,
+ 70482 => true,
+ 70483 => true,
+ 70484 => true,
+ 70485 => true,
+ 70486 => true,
+ 70488 => true,
+ 70489 => true,
+ 70490 => true,
+ 70491 => true,
+ 70492 => true,
+ 70500 => true,
+ 70501 => true,
+ 70509 => true,
+ 70510 => true,
+ 70511 => true,
+ 70748 => true,
+ 70754 => true,
+ 70755 => true,
+ 70756 => true,
+ 70757 => true,
+ 70758 => true,
+ 70759 => true,
+ 70760 => true,
+ 70761 => true,
+ 70762 => true,
+ 70763 => true,
+ 70764 => true,
+ 70765 => true,
+ 70766 => true,
+ 70767 => true,
+ 70768 => true,
+ 70769 => true,
+ 70770 => true,
+ 70771 => true,
+ 70772 => true,
+ 70773 => true,
+ 70774 => true,
+ 70775 => true,
+ 70776 => true,
+ 70777 => true,
+ 70778 => true,
+ 70779 => true,
+ 70780 => true,
+ 70781 => true,
+ 70782 => true,
+ 70783 => true,
+ 70856 => true,
+ 70857 => true,
+ 70858 => true,
+ 70859 => true,
+ 70860 => true,
+ 70861 => true,
+ 70862 => true,
+ 70863 => true,
+ 71094 => true,
+ 71095 => true,
+ 71237 => true,
+ 71238 => true,
+ 71239 => true,
+ 71240 => true,
+ 71241 => true,
+ 71242 => true,
+ 71243 => true,
+ 71244 => true,
+ 71245 => true,
+ 71246 => true,
+ 71247 => true,
+ 71258 => true,
+ 71259 => true,
+ 71260 => true,
+ 71261 => true,
+ 71262 => true,
+ 71263 => true,
+ 71277 => true,
+ 71278 => true,
+ 71279 => true,
+ 71280 => true,
+ 71281 => true,
+ 71282 => true,
+ 71283 => true,
+ 71284 => true,
+ 71285 => true,
+ 71286 => true,
+ 71287 => true,
+ 71288 => true,
+ 71289 => true,
+ 71290 => true,
+ 71291 => true,
+ 71292 => true,
+ 71293 => true,
+ 71294 => true,
+ 71295 => true,
+ 71353 => true,
+ 71354 => true,
+ 71355 => true,
+ 71356 => true,
+ 71357 => true,
+ 71358 => true,
+ 71359 => true,
+ 71451 => true,
+ 71452 => true,
+ 71468 => true,
+ 71469 => true,
+ 71470 => true,
+ 71471 => true,
+ 71923 => true,
+ 71924 => true,
+ 71925 => true,
+ 71926 => true,
+ 71927 => true,
+ 71928 => true,
+ 71929 => true,
+ 71930 => true,
+ 71931 => true,
+ 71932 => true,
+ 71933 => true,
+ 71934 => true,
+ 71943 => true,
+ 71944 => true,
+ 71946 => true,
+ 71947 => true,
+ 71956 => true,
+ 71959 => true,
+ 71990 => true,
+ 71993 => true,
+ 71994 => true,
+ 72007 => true,
+ 72008 => true,
+ 72009 => true,
+ 72010 => true,
+ 72011 => true,
+ 72012 => true,
+ 72013 => true,
+ 72014 => true,
+ 72015 => true,
+ 72104 => true,
+ 72105 => true,
+ 72152 => true,
+ 72153 => true,
+ 72165 => true,
+ 72166 => true,
+ 72167 => true,
+ 72168 => true,
+ 72169 => true,
+ 72170 => true,
+ 72171 => true,
+ 72172 => true,
+ 72173 => true,
+ 72174 => true,
+ 72175 => true,
+ 72176 => true,
+ 72177 => true,
+ 72178 => true,
+ 72179 => true,
+ 72180 => true,
+ 72181 => true,
+ 72182 => true,
+ 72183 => true,
+ 72184 => true,
+ 72185 => true,
+ 72186 => true,
+ 72187 => true,
+ 72188 => true,
+ 72189 => true,
+ 72190 => true,
+ 72191 => true,
+ 72264 => true,
+ 72265 => true,
+ 72266 => true,
+ 72267 => true,
+ 72268 => true,
+ 72269 => true,
+ 72270 => true,
+ 72271 => true,
+ 72355 => true,
+ 72356 => true,
+ 72357 => true,
+ 72358 => true,
+ 72359 => true,
+ 72360 => true,
+ 72361 => true,
+ 72362 => true,
+ 72363 => true,
+ 72364 => true,
+ 72365 => true,
+ 72366 => true,
+ 72367 => true,
+ 72368 => true,
+ 72369 => true,
+ 72370 => true,
+ 72371 => true,
+ 72372 => true,
+ 72373 => true,
+ 72374 => true,
+ 72375 => true,
+ 72376 => true,
+ 72377 => true,
+ 72378 => true,
+ 72379 => true,
+ 72380 => true,
+ 72381 => true,
+ 72382 => true,
+ 72383 => true,
+ 72713 => true,
+ 72759 => true,
+ 72774 => true,
+ 72775 => true,
+ 72776 => true,
+ 72777 => true,
+ 72778 => true,
+ 72779 => true,
+ 72780 => true,
+ 72781 => true,
+ 72782 => true,
+ 72783 => true,
+ 72813 => true,
+ 72814 => true,
+ 72815 => true,
+ 72848 => true,
+ 72849 => true,
+ 72872 => true,
+ 72967 => true,
+ 72970 => true,
+ 73015 => true,
+ 73016 => true,
+ 73017 => true,
+ 73019 => true,
+ 73022 => true,
+ 73032 => true,
+ 73033 => true,
+ 73034 => true,
+ 73035 => true,
+ 73036 => true,
+ 73037 => true,
+ 73038 => true,
+ 73039 => true,
+ 73050 => true,
+ 73051 => true,
+ 73052 => true,
+ 73053 => true,
+ 73054 => true,
+ 73055 => true,
+ 73062 => true,
+ 73065 => true,
+ 73103 => true,
+ 73106 => true,
+ 73113 => true,
+ 73114 => true,
+ 73115 => true,
+ 73116 => true,
+ 73117 => true,
+ 73118 => true,
+ 73119 => true,
+ 73649 => true,
+ 73650 => true,
+ 73651 => true,
+ 73652 => true,
+ 73653 => true,
+ 73654 => true,
+ 73655 => true,
+ 73656 => true,
+ 73657 => true,
+ 73658 => true,
+ 73659 => true,
+ 73660 => true,
+ 73661 => true,
+ 73662 => true,
+ 73663 => true,
+ 73714 => true,
+ 73715 => true,
+ 73716 => true,
+ 73717 => true,
+ 73718 => true,
+ 73719 => true,
+ 73720 => true,
+ 73721 => true,
+ 73722 => true,
+ 73723 => true,
+ 73724 => true,
+ 73725 => true,
+ 73726 => true,
+ 74863 => true,
+ 74869 => true,
+ 74870 => true,
+ 74871 => true,
+ 74872 => true,
+ 74873 => true,
+ 74874 => true,
+ 74875 => true,
+ 74876 => true,
+ 74877 => true,
+ 74878 => true,
+ 74879 => true,
+ 78895 => true,
+ 78896 => true,
+ 78897 => true,
+ 78898 => true,
+ 78899 => true,
+ 78900 => true,
+ 78901 => true,
+ 78902 => true,
+ 78903 => true,
+ 78904 => true,
+ 92729 => true,
+ 92730 => true,
+ 92731 => true,
+ 92732 => true,
+ 92733 => true,
+ 92734 => true,
+ 92735 => true,
+ 92767 => true,
+ 92778 => true,
+ 92779 => true,
+ 92780 => true,
+ 92781 => true,
+ 92910 => true,
+ 92911 => true,
+ 92918 => true,
+ 92919 => true,
+ 92920 => true,
+ 92921 => true,
+ 92922 => true,
+ 92923 => true,
+ 92924 => true,
+ 92925 => true,
+ 92926 => true,
+ 92927 => true,
+ 92998 => true,
+ 92999 => true,
+ 93000 => true,
+ 93001 => true,
+ 93002 => true,
+ 93003 => true,
+ 93004 => true,
+ 93005 => true,
+ 93006 => true,
+ 93007 => true,
+ 93018 => true,
+ 93026 => true,
+ 93048 => true,
+ 93049 => true,
+ 93050 => true,
+ 93051 => true,
+ 93052 => true,
+ 94027 => true,
+ 94028 => true,
+ 94029 => true,
+ 94030 => true,
+ 94088 => true,
+ 94089 => true,
+ 94090 => true,
+ 94091 => true,
+ 94092 => true,
+ 94093 => true,
+ 94094 => true,
+ 94181 => true,
+ 94182 => true,
+ 94183 => true,
+ 94184 => true,
+ 94185 => true,
+ 94186 => true,
+ 94187 => true,
+ 94188 => true,
+ 94189 => true,
+ 94190 => true,
+ 94191 => true,
+ 94194 => true,
+ 94195 => true,
+ 94196 => true,
+ 94197 => true,
+ 94198 => true,
+ 94199 => true,
+ 94200 => true,
+ 94201 => true,
+ 94202 => true,
+ 94203 => true,
+ 94204 => true,
+ 94205 => true,
+ 94206 => true,
+ 94207 => true,
+ 100344 => true,
+ 100345 => true,
+ 100346 => true,
+ 100347 => true,
+ 100348 => true,
+ 100349 => true,
+ 100350 => true,
+ 100351 => true,
+ 110931 => true,
+ 110932 => true,
+ 110933 => true,
+ 110934 => true,
+ 110935 => true,
+ 110936 => true,
+ 110937 => true,
+ 110938 => true,
+ 110939 => true,
+ 110940 => true,
+ 110941 => true,
+ 110942 => true,
+ 110943 => true,
+ 110944 => true,
+ 110945 => true,
+ 110946 => true,
+ 110947 => true,
+ 110952 => true,
+ 110953 => true,
+ 110954 => true,
+ 110955 => true,
+ 110956 => true,
+ 110957 => true,
+ 110958 => true,
+ 110959 => true,
+ 113771 => true,
+ 113772 => true,
+ 113773 => true,
+ 113774 => true,
+ 113775 => true,
+ 113789 => true,
+ 113790 => true,
+ 113791 => true,
+ 113801 => true,
+ 113802 => true,
+ 113803 => true,
+ 113804 => true,
+ 113805 => true,
+ 113806 => true,
+ 113807 => true,
+ 113818 => true,
+ 113819 => true,
+ 119030 => true,
+ 119031 => true,
+ 119032 => true,
+ 119033 => true,
+ 119034 => true,
+ 119035 => true,
+ 119036 => true,
+ 119037 => true,
+ 119038 => true,
+ 119039 => true,
+ 119079 => true,
+ 119080 => true,
+ 119155 => true,
+ 119156 => true,
+ 119157 => true,
+ 119158 => true,
+ 119159 => true,
+ 119160 => true,
+ 119161 => true,
+ 119162 => true,
+ 119273 => true,
+ 119274 => true,
+ 119275 => true,
+ 119276 => true,
+ 119277 => true,
+ 119278 => true,
+ 119279 => true,
+ 119280 => true,
+ 119281 => true,
+ 119282 => true,
+ 119283 => true,
+ 119284 => true,
+ 119285 => true,
+ 119286 => true,
+ 119287 => true,
+ 119288 => true,
+ 119289 => true,
+ 119290 => true,
+ 119291 => true,
+ 119292 => true,
+ 119293 => true,
+ 119294 => true,
+ 119295 => true,
+ 119540 => true,
+ 119541 => true,
+ 119542 => true,
+ 119543 => true,
+ 119544 => true,
+ 119545 => true,
+ 119546 => true,
+ 119547 => true,
+ 119548 => true,
+ 119549 => true,
+ 119550 => true,
+ 119551 => true,
+ 119639 => true,
+ 119640 => true,
+ 119641 => true,
+ 119642 => true,
+ 119643 => true,
+ 119644 => true,
+ 119645 => true,
+ 119646 => true,
+ 119647 => true,
+ 119893 => true,
+ 119965 => true,
+ 119968 => true,
+ 119969 => true,
+ 119971 => true,
+ 119972 => true,
+ 119975 => true,
+ 119976 => true,
+ 119981 => true,
+ 119994 => true,
+ 119996 => true,
+ 120004 => true,
+ 120070 => true,
+ 120075 => true,
+ 120076 => true,
+ 120085 => true,
+ 120093 => true,
+ 120122 => true,
+ 120127 => true,
+ 120133 => true,
+ 120135 => true,
+ 120136 => true,
+ 120137 => true,
+ 120145 => true,
+ 120486 => true,
+ 120487 => true,
+ 120780 => true,
+ 120781 => true,
+ 121484 => true,
+ 121485 => true,
+ 121486 => true,
+ 121487 => true,
+ 121488 => true,
+ 121489 => true,
+ 121490 => true,
+ 121491 => true,
+ 121492 => true,
+ 121493 => true,
+ 121494 => true,
+ 121495 => true,
+ 121496 => true,
+ 121497 => true,
+ 121498 => true,
+ 121504 => true,
+ 122887 => true,
+ 122905 => true,
+ 122906 => true,
+ 122914 => true,
+ 122917 => true,
+ 123181 => true,
+ 123182 => true,
+ 123183 => true,
+ 123198 => true,
+ 123199 => true,
+ 123210 => true,
+ 123211 => true,
+ 123212 => true,
+ 123213 => true,
+ 123642 => true,
+ 123643 => true,
+ 123644 => true,
+ 123645 => true,
+ 123646 => true,
+ 125125 => true,
+ 125126 => true,
+ 125260 => true,
+ 125261 => true,
+ 125262 => true,
+ 125263 => true,
+ 125274 => true,
+ 125275 => true,
+ 125276 => true,
+ 125277 => true,
+ 126468 => true,
+ 126496 => true,
+ 126499 => true,
+ 126501 => true,
+ 126502 => true,
+ 126504 => true,
+ 126515 => true,
+ 126520 => true,
+ 126522 => true,
+ 126524 => true,
+ 126525 => true,
+ 126526 => true,
+ 126527 => true,
+ 126528 => true,
+ 126529 => true,
+ 126531 => true,
+ 126532 => true,
+ 126533 => true,
+ 126534 => true,
+ 126536 => true,
+ 126538 => true,
+ 126540 => true,
+ 126544 => true,
+ 126547 => true,
+ 126549 => true,
+ 126550 => true,
+ 126552 => true,
+ 126554 => true,
+ 126556 => true,
+ 126558 => true,
+ 126560 => true,
+ 126563 => true,
+ 126565 => true,
+ 126566 => true,
+ 126571 => true,
+ 126579 => true,
+ 126584 => true,
+ 126589 => true,
+ 126591 => true,
+ 126602 => true,
+ 126620 => true,
+ 126621 => true,
+ 126622 => true,
+ 126623 => true,
+ 126624 => true,
+ 126628 => true,
+ 126634 => true,
+ 127020 => true,
+ 127021 => true,
+ 127022 => true,
+ 127023 => true,
+ 127124 => true,
+ 127125 => true,
+ 127126 => true,
+ 127127 => true,
+ 127128 => true,
+ 127129 => true,
+ 127130 => true,
+ 127131 => true,
+ 127132 => true,
+ 127133 => true,
+ 127134 => true,
+ 127135 => true,
+ 127151 => true,
+ 127152 => true,
+ 127168 => true,
+ 127184 => true,
+ 127222 => true,
+ 127223 => true,
+ 127224 => true,
+ 127225 => true,
+ 127226 => true,
+ 127227 => true,
+ 127228 => true,
+ 127229 => true,
+ 127230 => true,
+ 127231 => true,
+ 127232 => true,
+ 127491 => true,
+ 127492 => true,
+ 127493 => true,
+ 127494 => true,
+ 127495 => true,
+ 127496 => true,
+ 127497 => true,
+ 127498 => true,
+ 127499 => true,
+ 127500 => true,
+ 127501 => true,
+ 127502 => true,
+ 127503 => true,
+ 127548 => true,
+ 127549 => true,
+ 127550 => true,
+ 127551 => true,
+ 127561 => true,
+ 127562 => true,
+ 127563 => true,
+ 127564 => true,
+ 127565 => true,
+ 127566 => true,
+ 127567 => true,
+ 127570 => true,
+ 127571 => true,
+ 127572 => true,
+ 127573 => true,
+ 127574 => true,
+ 127575 => true,
+ 127576 => true,
+ 127577 => true,
+ 127578 => true,
+ 127579 => true,
+ 127580 => true,
+ 127581 => true,
+ 127582 => true,
+ 127583 => true,
+ 128728 => true,
+ 128729 => true,
+ 128730 => true,
+ 128731 => true,
+ 128732 => true,
+ 128733 => true,
+ 128734 => true,
+ 128735 => true,
+ 128749 => true,
+ 128750 => true,
+ 128751 => true,
+ 128765 => true,
+ 128766 => true,
+ 128767 => true,
+ 128884 => true,
+ 128885 => true,
+ 128886 => true,
+ 128887 => true,
+ 128888 => true,
+ 128889 => true,
+ 128890 => true,
+ 128891 => true,
+ 128892 => true,
+ 128893 => true,
+ 128894 => true,
+ 128895 => true,
+ 128985 => true,
+ 128986 => true,
+ 128987 => true,
+ 128988 => true,
+ 128989 => true,
+ 128990 => true,
+ 128991 => true,
+ 129004 => true,
+ 129005 => true,
+ 129006 => true,
+ 129007 => true,
+ 129008 => true,
+ 129009 => true,
+ 129010 => true,
+ 129011 => true,
+ 129012 => true,
+ 129013 => true,
+ 129014 => true,
+ 129015 => true,
+ 129016 => true,
+ 129017 => true,
+ 129018 => true,
+ 129019 => true,
+ 129020 => true,
+ 129021 => true,
+ 129022 => true,
+ 129023 => true,
+ 129036 => true,
+ 129037 => true,
+ 129038 => true,
+ 129039 => true,
+ 129096 => true,
+ 129097 => true,
+ 129098 => true,
+ 129099 => true,
+ 129100 => true,
+ 129101 => true,
+ 129102 => true,
+ 129103 => true,
+ 129114 => true,
+ 129115 => true,
+ 129116 => true,
+ 129117 => true,
+ 129118 => true,
+ 129119 => true,
+ 129160 => true,
+ 129161 => true,
+ 129162 => true,
+ 129163 => true,
+ 129164 => true,
+ 129165 => true,
+ 129166 => true,
+ 129167 => true,
+ 129198 => true,
+ 129199 => true,
+ 129401 => true,
+ 129484 => true,
+ 129620 => true,
+ 129621 => true,
+ 129622 => true,
+ 129623 => true,
+ 129624 => true,
+ 129625 => true,
+ 129626 => true,
+ 129627 => true,
+ 129628 => true,
+ 129629 => true,
+ 129630 => true,
+ 129631 => true,
+ 129646 => true,
+ 129647 => true,
+ 129653 => true,
+ 129654 => true,
+ 129655 => true,
+ 129659 => true,
+ 129660 => true,
+ 129661 => true,
+ 129662 => true,
+ 129663 => true,
+ 129671 => true,
+ 129672 => true,
+ 129673 => true,
+ 129674 => true,
+ 129675 => true,
+ 129676 => true,
+ 129677 => true,
+ 129678 => true,
+ 129679 => true,
+ 129705 => true,
+ 129706 => true,
+ 129707 => true,
+ 129708 => true,
+ 129709 => true,
+ 129710 => true,
+ 129711 => true,
+ 129719 => true,
+ 129720 => true,
+ 129721 => true,
+ 129722 => true,
+ 129723 => true,
+ 129724 => true,
+ 129725 => true,
+ 129726 => true,
+ 129727 => true,
+ 129731 => true,
+ 129732 => true,
+ 129733 => true,
+ 129734 => true,
+ 129735 => true,
+ 129736 => true,
+ 129737 => true,
+ 129738 => true,
+ 129739 => true,
+ 129740 => true,
+ 129741 => true,
+ 129742 => true,
+ 129743 => true,
+ 129939 => true,
+ 131070 => true,
+ 131071 => true,
+ 177973 => true,
+ 177974 => true,
+ 177975 => true,
+ 177976 => true,
+ 177977 => true,
+ 177978 => true,
+ 177979 => true,
+ 177980 => true,
+ 177981 => true,
+ 177982 => true,
+ 177983 => true,
+ 178206 => true,
+ 178207 => true,
+ 183970 => true,
+ 183971 => true,
+ 183972 => true,
+ 183973 => true,
+ 183974 => true,
+ 183975 => true,
+ 183976 => true,
+ 183977 => true,
+ 183978 => true,
+ 183979 => true,
+ 183980 => true,
+ 183981 => true,
+ 183982 => true,
+ 183983 => true,
+ 194664 => true,
+ 194676 => true,
+ 194847 => true,
+ 194911 => true,
+ 195007 => true,
+ 196606 => true,
+ 196607 => true,
+ 262142 => true,
+ 262143 => true,
+ 327678 => true,
+ 327679 => true,
+ 393214 => true,
+ 393215 => true,
+ 458750 => true,
+ 458751 => true,
+ 524286 => true,
+ 524287 => true,
+ 589822 => true,
+ 589823 => true,
+ 655358 => true,
+ 655359 => true,
+ 720894 => true,
+ 720895 => true,
+ 786430 => true,
+ 786431 => true,
+ 851966 => true,
+ 851967 => true,
+ 917502 => true,
+ 917503 => true,
+ 917504 => true,
+ 917505 => true,
+ 917506 => true,
+ 917507 => true,
+ 917508 => true,
+ 917509 => true,
+ 917510 => true,
+ 917511 => true,
+ 917512 => true,
+ 917513 => true,
+ 917514 => true,
+ 917515 => true,
+ 917516 => true,
+ 917517 => true,
+ 917518 => true,
+ 917519 => true,
+ 917520 => true,
+ 917521 => true,
+ 917522 => true,
+ 917523 => true,
+ 917524 => true,
+ 917525 => true,
+ 917526 => true,
+ 917527 => true,
+ 917528 => true,
+ 917529 => true,
+ 917530 => true,
+ 917531 => true,
+ 917532 => true,
+ 917533 => true,
+ 917534 => true,
+ 917535 => true,
+ 983038 => true,
+ 983039 => true,
+ 1048574 => true,
+ 1048575 => true,
+ 1114110 => true,
+ 1114111 => true,
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php
new file mode 100644
index 0000000..54f21cc
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php
@@ -0,0 +1,308 @@
+<?php
+
+return array (
+ 160 => ' ',
+ 168 => ' ̈',
+ 175 => ' ̄',
+ 180 => ' ́',
+ 184 => ' ̧',
+ 728 => ' ̆',
+ 729 => ' ̇',
+ 730 => ' ̊',
+ 731 => ' ̨',
+ 732 => ' ̃',
+ 733 => ' ̋',
+ 890 => ' ι',
+ 894 => ';',
+ 900 => ' ́',
+ 901 => ' ̈́',
+ 8125 => ' ̓',
+ 8127 => ' ̓',
+ 8128 => ' ͂',
+ 8129 => ' ̈͂',
+ 8141 => ' ̓̀',
+ 8142 => ' ̓́',
+ 8143 => ' ̓͂',
+ 8157 => ' ̔̀',
+ 8158 => ' ̔́',
+ 8159 => ' ̔͂',
+ 8173 => ' ̈̀',
+ 8174 => ' ̈́',
+ 8175 => '`',
+ 8189 => ' ́',
+ 8190 => ' ̔',
+ 8192 => ' ',
+ 8193 => ' ',
+ 8194 => ' ',
+ 8195 => ' ',
+ 8196 => ' ',
+ 8197 => ' ',
+ 8198 => ' ',
+ 8199 => ' ',
+ 8200 => ' ',
+ 8201 => ' ',
+ 8202 => ' ',
+ 8215 => ' ̳',
+ 8239 => ' ',
+ 8252 => '!!',
+ 8254 => ' ̅',
+ 8263 => '??',
+ 8264 => '?!',
+ 8265 => '!?',
+ 8287 => ' ',
+ 8314 => '+',
+ 8316 => '=',
+ 8317 => '(',
+ 8318 => ')',
+ 8330 => '+',
+ 8332 => '=',
+ 8333 => '(',
+ 8334 => ')',
+ 8448 => 'a/c',
+ 8449 => 'a/s',
+ 8453 => 'c/o',
+ 8454 => 'c/u',
+ 9332 => '(1)',
+ 9333 => '(2)',
+ 9334 => '(3)',
+ 9335 => '(4)',
+ 9336 => '(5)',
+ 9337 => '(6)',
+ 9338 => '(7)',
+ 9339 => '(8)',
+ 9340 => '(9)',
+ 9341 => '(10)',
+ 9342 => '(11)',
+ 9343 => '(12)',
+ 9344 => '(13)',
+ 9345 => '(14)',
+ 9346 => '(15)',
+ 9347 => '(16)',
+ 9348 => '(17)',
+ 9349 => '(18)',
+ 9350 => '(19)',
+ 9351 => '(20)',
+ 9372 => '(a)',
+ 9373 => '(b)',
+ 9374 => '(c)',
+ 9375 => '(d)',
+ 9376 => '(e)',
+ 9377 => '(f)',
+ 9378 => '(g)',
+ 9379 => '(h)',
+ 9380 => '(i)',
+ 9381 => '(j)',
+ 9382 => '(k)',
+ 9383 => '(l)',
+ 9384 => '(m)',
+ 9385 => '(n)',
+ 9386 => '(o)',
+ 9387 => '(p)',
+ 9388 => '(q)',
+ 9389 => '(r)',
+ 9390 => '(s)',
+ 9391 => '(t)',
+ 9392 => '(u)',
+ 9393 => '(v)',
+ 9394 => '(w)',
+ 9395 => '(x)',
+ 9396 => '(y)',
+ 9397 => '(z)',
+ 10868 => '::=',
+ 10869 => '==',
+ 10870 => '===',
+ 12288 => ' ',
+ 12443 => ' ゙',
+ 12444 => ' ゚',
+ 12800 => '(ᄀ)',
+ 12801 => '(ᄂ)',
+ 12802 => '(ᄃ)',
+ 12803 => '(ᄅ)',
+ 12804 => '(ᄆ)',
+ 12805 => '(ᄇ)',
+ 12806 => '(ᄉ)',
+ 12807 => '(ᄋ)',
+ 12808 => '(ᄌ)',
+ 12809 => '(ᄎ)',
+ 12810 => '(ᄏ)',
+ 12811 => '(ᄐ)',
+ 12812 => '(ᄑ)',
+ 12813 => '(ᄒ)',
+ 12814 => '(가)',
+ 12815 => '(나)',
+ 12816 => '(다)',
+ 12817 => '(라)',
+ 12818 => '(마)',
+ 12819 => '(바)',
+ 12820 => '(사)',
+ 12821 => '(아)',
+ 12822 => '(자)',
+ 12823 => '(차)',
+ 12824 => '(카)',
+ 12825 => '(타)',
+ 12826 => '(파)',
+ 12827 => '(하)',
+ 12828 => '(주)',
+ 12829 => '(오전)',
+ 12830 => '(오후)',
+ 12832 => '(一)',
+ 12833 => '(二)',
+ 12834 => '(三)',
+ 12835 => '(四)',
+ 12836 => '(五)',
+ 12837 => '(六)',
+ 12838 => '(七)',
+ 12839 => '(八)',
+ 12840 => '(九)',
+ 12841 => '(十)',
+ 12842 => '(月)',
+ 12843 => '(火)',
+ 12844 => '(水)',
+ 12845 => '(木)',
+ 12846 => '(金)',
+ 12847 => '(土)',
+ 12848 => '(日)',
+ 12849 => '(株)',
+ 12850 => '(有)',
+ 12851 => '(社)',
+ 12852 => '(名)',
+ 12853 => '(特)',
+ 12854 => '(財)',
+ 12855 => '(祝)',
+ 12856 => '(労)',
+ 12857 => '(代)',
+ 12858 => '(呼)',
+ 12859 => '(学)',
+ 12860 => '(監)',
+ 12861 => '(企)',
+ 12862 => '(資)',
+ 12863 => '(協)',
+ 12864 => '(祭)',
+ 12865 => '(休)',
+ 12866 => '(自)',
+ 12867 => '(至)',
+ 64297 => '+',
+ 64606 => ' ٌّ',
+ 64607 => ' ٍّ',
+ 64608 => ' َّ',
+ 64609 => ' ُّ',
+ 64610 => ' ِّ',
+ 64611 => ' ّٰ',
+ 65018 => 'صلى الله عليه وسلم',
+ 65019 => 'جل جلاله',
+ 65040 => ',',
+ 65043 => ':',
+ 65044 => ';',
+ 65045 => '!',
+ 65046 => '?',
+ 65075 => '_',
+ 65076 => '_',
+ 65077 => '(',
+ 65078 => ')',
+ 65079 => '{',
+ 65080 => '}',
+ 65095 => '[',
+ 65096 => ']',
+ 65097 => ' ̅',
+ 65098 => ' ̅',
+ 65099 => ' ̅',
+ 65100 => ' ̅',
+ 65101 => '_',
+ 65102 => '_',
+ 65103 => '_',
+ 65104 => ',',
+ 65108 => ';',
+ 65109 => ':',
+ 65110 => '?',
+ 65111 => '!',
+ 65113 => '(',
+ 65114 => ')',
+ 65115 => '{',
+ 65116 => '}',
+ 65119 => '#',
+ 65120 => '&',
+ 65121 => '*',
+ 65122 => '+',
+ 65124 => '<',
+ 65125 => '>',
+ 65126 => '=',
+ 65128 => '\\',
+ 65129 => '$',
+ 65130 => '%',
+ 65131 => '@',
+ 65136 => ' ً',
+ 65138 => ' ٌ',
+ 65140 => ' ٍ',
+ 65142 => ' َ',
+ 65144 => ' ُ',
+ 65146 => ' ِ',
+ 65148 => ' ّ',
+ 65150 => ' ْ',
+ 65281 => '!',
+ 65282 => '"',
+ 65283 => '#',
+ 65284 => '$',
+ 65285 => '%',
+ 65286 => '&',
+ 65287 => '\'',
+ 65288 => '(',
+ 65289 => ')',
+ 65290 => '*',
+ 65291 => '+',
+ 65292 => ',',
+ 65295 => '/',
+ 65306 => ':',
+ 65307 => ';',
+ 65308 => '<',
+ 65309 => '=',
+ 65310 => '>',
+ 65311 => '?',
+ 65312 => '@',
+ 65339 => '[',
+ 65340 => '\\',
+ 65341 => ']',
+ 65342 => '^',
+ 65343 => '_',
+ 65344 => '`',
+ 65371 => '{',
+ 65372 => '|',
+ 65373 => '}',
+ 65374 => '~',
+ 65507 => ' ̄',
+ 127233 => '0,',
+ 127234 => '1,',
+ 127235 => '2,',
+ 127236 => '3,',
+ 127237 => '4,',
+ 127238 => '5,',
+ 127239 => '6,',
+ 127240 => '7,',
+ 127241 => '8,',
+ 127242 => '9,',
+ 127248 => '(a)',
+ 127249 => '(b)',
+ 127250 => '(c)',
+ 127251 => '(d)',
+ 127252 => '(e)',
+ 127253 => '(f)',
+ 127254 => '(g)',
+ 127255 => '(h)',
+ 127256 => '(i)',
+ 127257 => '(j)',
+ 127258 => '(k)',
+ 127259 => '(l)',
+ 127260 => '(m)',
+ 127261 => '(n)',
+ 127262 => '(o)',
+ 127263 => '(p)',
+ 127264 => '(q)',
+ 127265 => '(r)',
+ 127266 => '(s)',
+ 127267 => '(t)',
+ 127268 => '(u)',
+ 127269 => '(v)',
+ 127270 => '(w)',
+ 127271 => '(x)',
+ 127272 => '(y)',
+ 127273 => '(z)',
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php
new file mode 100644
index 0000000..223396e
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php
@@ -0,0 +1,71 @@
+<?php
+
+return array (
+ 0 => true,
+ 1 => true,
+ 2 => true,
+ 3 => true,
+ 4 => true,
+ 5 => true,
+ 6 => true,
+ 7 => true,
+ 8 => true,
+ 9 => true,
+ 10 => true,
+ 11 => true,
+ 12 => true,
+ 13 => true,
+ 14 => true,
+ 15 => true,
+ 16 => true,
+ 17 => true,
+ 18 => true,
+ 19 => true,
+ 20 => true,
+ 21 => true,
+ 22 => true,
+ 23 => true,
+ 24 => true,
+ 25 => true,
+ 26 => true,
+ 27 => true,
+ 28 => true,
+ 29 => true,
+ 30 => true,
+ 31 => true,
+ 32 => true,
+ 33 => true,
+ 34 => true,
+ 35 => true,
+ 36 => true,
+ 37 => true,
+ 38 => true,
+ 39 => true,
+ 40 => true,
+ 41 => true,
+ 42 => true,
+ 43 => true,
+ 44 => true,
+ 47 => true,
+ 58 => true,
+ 59 => true,
+ 60 => true,
+ 61 => true,
+ 62 => true,
+ 63 => true,
+ 64 => true,
+ 91 => true,
+ 92 => true,
+ 93 => true,
+ 94 => true,
+ 95 => true,
+ 96 => true,
+ 123 => true,
+ 124 => true,
+ 125 => true,
+ 126 => true,
+ 127 => true,
+ 8800 => true,
+ 8814 => true,
+ 8815 => true,
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php
new file mode 100644
index 0000000..b377844
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php
@@ -0,0 +1,273 @@
+<?php
+
+return array (
+ 173 => true,
+ 847 => true,
+ 6155 => true,
+ 6156 => true,
+ 6157 => true,
+ 8203 => true,
+ 8288 => true,
+ 8292 => true,
+ 65024 => true,
+ 65025 => true,
+ 65026 => true,
+ 65027 => true,
+ 65028 => true,
+ 65029 => true,
+ 65030 => true,
+ 65031 => true,
+ 65032 => true,
+ 65033 => true,
+ 65034 => true,
+ 65035 => true,
+ 65036 => true,
+ 65037 => true,
+ 65038 => true,
+ 65039 => true,
+ 65279 => true,
+ 113824 => true,
+ 113825 => true,
+ 113826 => true,
+ 113827 => true,
+ 917760 => true,
+ 917761 => true,
+ 917762 => true,
+ 917763 => true,
+ 917764 => true,
+ 917765 => true,
+ 917766 => true,
+ 917767 => true,
+ 917768 => true,
+ 917769 => true,
+ 917770 => true,
+ 917771 => true,
+ 917772 => true,
+ 917773 => true,
+ 917774 => true,
+ 917775 => true,
+ 917776 => true,
+ 917777 => true,
+ 917778 => true,
+ 917779 => true,
+ 917780 => true,
+ 917781 => true,
+ 917782 => true,
+ 917783 => true,
+ 917784 => true,
+ 917785 => true,
+ 917786 => true,
+ 917787 => true,
+ 917788 => true,
+ 917789 => true,
+ 917790 => true,
+ 917791 => true,
+ 917792 => true,
+ 917793 => true,
+ 917794 => true,
+ 917795 => true,
+ 917796 => true,
+ 917797 => true,
+ 917798 => true,
+ 917799 => true,
+ 917800 => true,
+ 917801 => true,
+ 917802 => true,
+ 917803 => true,
+ 917804 => true,
+ 917805 => true,
+ 917806 => true,
+ 917807 => true,
+ 917808 => true,
+ 917809 => true,
+ 917810 => true,
+ 917811 => true,
+ 917812 => true,
+ 917813 => true,
+ 917814 => true,
+ 917815 => true,
+ 917816 => true,
+ 917817 => true,
+ 917818 => true,
+ 917819 => true,
+ 917820 => true,
+ 917821 => true,
+ 917822 => true,
+ 917823 => true,
+ 917824 => true,
+ 917825 => true,
+ 917826 => true,
+ 917827 => true,
+ 917828 => true,
+ 917829 => true,
+ 917830 => true,
+ 917831 => true,
+ 917832 => true,
+ 917833 => true,
+ 917834 => true,
+ 917835 => true,
+ 917836 => true,
+ 917837 => true,
+ 917838 => true,
+ 917839 => true,
+ 917840 => true,
+ 917841 => true,
+ 917842 => true,
+ 917843 => true,
+ 917844 => true,
+ 917845 => true,
+ 917846 => true,
+ 917847 => true,
+ 917848 => true,
+ 917849 => true,
+ 917850 => true,
+ 917851 => true,
+ 917852 => true,
+ 917853 => true,
+ 917854 => true,
+ 917855 => true,
+ 917856 => true,
+ 917857 => true,
+ 917858 => true,
+ 917859 => true,
+ 917860 => true,
+ 917861 => true,
+ 917862 => true,
+ 917863 => true,
+ 917864 => true,
+ 917865 => true,
+ 917866 => true,
+ 917867 => true,
+ 917868 => true,
+ 917869 => true,
+ 917870 => true,
+ 917871 => true,
+ 917872 => true,
+ 917873 => true,
+ 917874 => true,
+ 917875 => true,
+ 917876 => true,
+ 917877 => true,
+ 917878 => true,
+ 917879 => true,
+ 917880 => true,
+ 917881 => true,
+ 917882 => true,
+ 917883 => true,
+ 917884 => true,
+ 917885 => true,
+ 917886 => true,
+ 917887 => true,
+ 917888 => true,
+ 917889 => true,
+ 917890 => true,
+ 917891 => true,
+ 917892 => true,
+ 917893 => true,
+ 917894 => true,
+ 917895 => true,
+ 917896 => true,
+ 917897 => true,
+ 917898 => true,
+ 917899 => true,
+ 917900 => true,
+ 917901 => true,
+ 917902 => true,
+ 917903 => true,
+ 917904 => true,
+ 917905 => true,
+ 917906 => true,
+ 917907 => true,
+ 917908 => true,
+ 917909 => true,
+ 917910 => true,
+ 917911 => true,
+ 917912 => true,
+ 917913 => true,
+ 917914 => true,
+ 917915 => true,
+ 917916 => true,
+ 917917 => true,
+ 917918 => true,
+ 917919 => true,
+ 917920 => true,
+ 917921 => true,
+ 917922 => true,
+ 917923 => true,
+ 917924 => true,
+ 917925 => true,
+ 917926 => true,
+ 917927 => true,
+ 917928 => true,
+ 917929 => true,
+ 917930 => true,
+ 917931 => true,
+ 917932 => true,
+ 917933 => true,
+ 917934 => true,
+ 917935 => true,
+ 917936 => true,
+ 917937 => true,
+ 917938 => true,
+ 917939 => true,
+ 917940 => true,
+ 917941 => true,
+ 917942 => true,
+ 917943 => true,
+ 917944 => true,
+ 917945 => true,
+ 917946 => true,
+ 917947 => true,
+ 917948 => true,
+ 917949 => true,
+ 917950 => true,
+ 917951 => true,
+ 917952 => true,
+ 917953 => true,
+ 917954 => true,
+ 917955 => true,
+ 917956 => true,
+ 917957 => true,
+ 917958 => true,
+ 917959 => true,
+ 917960 => true,
+ 917961 => true,
+ 917962 => true,
+ 917963 => true,
+ 917964 => true,
+ 917965 => true,
+ 917966 => true,
+ 917967 => true,
+ 917968 => true,
+ 917969 => true,
+ 917970 => true,
+ 917971 => true,
+ 917972 => true,
+ 917973 => true,
+ 917974 => true,
+ 917975 => true,
+ 917976 => true,
+ 917977 => true,
+ 917978 => true,
+ 917979 => true,
+ 917980 => true,
+ 917981 => true,
+ 917982 => true,
+ 917983 => true,
+ 917984 => true,
+ 917985 => true,
+ 917986 => true,
+ 917987 => true,
+ 917988 => true,
+ 917989 => true,
+ 917990 => true,
+ 917991 => true,
+ 917992 => true,
+ 917993 => true,
+ 917994 => true,
+ 917995 => true,
+ 917996 => true,
+ 917997 => true,
+ 917998 => true,
+ 917999 => true,
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php
new file mode 100644
index 0000000..9b85fe9
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php
@@ -0,0 +1,5778 @@
+<?php
+
+return array (
+ 65 => 'a',
+ 66 => 'b',
+ 67 => 'c',
+ 68 => 'd',
+ 69 => 'e',
+ 70 => 'f',
+ 71 => 'g',
+ 72 => 'h',
+ 73 => 'i',
+ 74 => 'j',
+ 75 => 'k',
+ 76 => 'l',
+ 77 => 'm',
+ 78 => 'n',
+ 79 => 'o',
+ 80 => 'p',
+ 81 => 'q',
+ 82 => 'r',
+ 83 => 's',
+ 84 => 't',
+ 85 => 'u',
+ 86 => 'v',
+ 87 => 'w',
+ 88 => 'x',
+ 89 => 'y',
+ 90 => 'z',
+ 170 => 'a',
+ 178 => '2',
+ 179 => '3',
+ 181 => 'μ',
+ 185 => '1',
+ 186 => 'o',
+ 188 => '1⁄4',
+ 189 => '1⁄2',
+ 190 => '3⁄4',
+ 192 => 'à',
+ 193 => 'á',
+ 194 => 'â',
+ 195 => 'ã',
+ 196 => 'ä',
+ 197 => 'å',
+ 198 => 'æ',
+ 199 => 'ç',
+ 200 => 'è',
+ 201 => 'é',
+ 202 => 'ê',
+ 203 => 'ë',
+ 204 => 'ì',
+ 205 => 'í',
+ 206 => 'î',
+ 207 => 'ï',
+ 208 => 'ð',
+ 209 => 'ñ',
+ 210 => 'ò',
+ 211 => 'ó',
+ 212 => 'ô',
+ 213 => 'õ',
+ 214 => 'ö',
+ 216 => 'ø',
+ 217 => 'ù',
+ 218 => 'ú',
+ 219 => 'û',
+ 220 => 'ü',
+ 221 => 'ý',
+ 222 => 'þ',
+ 256 => 'ā',
+ 258 => 'ă',
+ 260 => 'ą',
+ 262 => 'ć',
+ 264 => 'ĉ',
+ 266 => 'ċ',
+ 268 => 'č',
+ 270 => 'ď',
+ 272 => 'đ',
+ 274 => 'ē',
+ 276 => 'ĕ',
+ 278 => 'ė',
+ 280 => 'ę',
+ 282 => 'ě',
+ 284 => 'ĝ',
+ 286 => 'ğ',
+ 288 => 'ġ',
+ 290 => 'ģ',
+ 292 => 'ĥ',
+ 294 => 'ħ',
+ 296 => 'ĩ',
+ 298 => 'ī',
+ 300 => 'ĭ',
+ 302 => 'į',
+ 304 => 'i̇',
+ 306 => 'ij',
+ 307 => 'ij',
+ 308 => 'ĵ',
+ 310 => 'ķ',
+ 313 => 'ĺ',
+ 315 => 'ļ',
+ 317 => 'ľ',
+ 319 => 'l·',
+ 320 => 'l·',
+ 321 => 'ł',
+ 323 => 'ń',
+ 325 => 'ņ',
+ 327 => 'ň',
+ 329 => 'ʼn',
+ 330 => 'ŋ',
+ 332 => 'ō',
+ 334 => 'ŏ',
+ 336 => 'ő',
+ 338 => 'œ',
+ 340 => 'ŕ',
+ 342 => 'ŗ',
+ 344 => 'ř',
+ 346 => 'ś',
+ 348 => 'ŝ',
+ 350 => 'ş',
+ 352 => 'š',
+ 354 => 'ţ',
+ 356 => 'ť',
+ 358 => 'ŧ',
+ 360 => 'ũ',
+ 362 => 'ū',
+ 364 => 'ŭ',
+ 366 => 'ů',
+ 368 => 'ű',
+ 370 => 'ų',
+ 372 => 'ŵ',
+ 374 => 'ŷ',
+ 376 => 'ÿ',
+ 377 => 'ź',
+ 379 => 'ż',
+ 381 => 'ž',
+ 383 => 's',
+ 385 => 'ɓ',
+ 386 => 'ƃ',
+ 388 => 'ƅ',
+ 390 => 'ɔ',
+ 391 => 'ƈ',
+ 393 => 'ɖ',
+ 394 => 'ɗ',
+ 395 => 'ƌ',
+ 398 => 'ǝ',
+ 399 => 'ə',
+ 400 => 'ɛ',
+ 401 => 'ƒ',
+ 403 => 'ɠ',
+ 404 => 'ɣ',
+ 406 => 'ɩ',
+ 407 => 'ɨ',
+ 408 => 'ƙ',
+ 412 => 'ɯ',
+ 413 => 'ɲ',
+ 415 => 'ɵ',
+ 416 => 'ơ',
+ 418 => 'ƣ',
+ 420 => 'ƥ',
+ 422 => 'ʀ',
+ 423 => 'ƨ',
+ 425 => 'ʃ',
+ 428 => 'ƭ',
+ 430 => 'ʈ',
+ 431 => 'ư',
+ 433 => 'ʊ',
+ 434 => 'ʋ',
+ 435 => 'ƴ',
+ 437 => 'ƶ',
+ 439 => 'ʒ',
+ 440 => 'ƹ',
+ 444 => 'ƽ',
+ 452 => 'dž',
+ 453 => 'dž',
+ 454 => 'dž',
+ 455 => 'lj',
+ 456 => 'lj',
+ 457 => 'lj',
+ 458 => 'nj',
+ 459 => 'nj',
+ 460 => 'nj',
+ 461 => 'ǎ',
+ 463 => 'ǐ',
+ 465 => 'ǒ',
+ 467 => 'ǔ',
+ 469 => 'ǖ',
+ 471 => 'ǘ',
+ 473 => 'ǚ',
+ 475 => 'ǜ',
+ 478 => 'ǟ',
+ 480 => 'ǡ',
+ 482 => 'ǣ',
+ 484 => 'ǥ',
+ 486 => 'ǧ',
+ 488 => 'ǩ',
+ 490 => 'ǫ',
+ 492 => 'ǭ',
+ 494 => 'ǯ',
+ 497 => 'dz',
+ 498 => 'dz',
+ 499 => 'dz',
+ 500 => 'ǵ',
+ 502 => 'ƕ',
+ 503 => 'ƿ',
+ 504 => 'ǹ',
+ 506 => 'ǻ',
+ 508 => 'ǽ',
+ 510 => 'ǿ',
+ 512 => 'ȁ',
+ 514 => 'ȃ',
+ 516 => 'ȅ',
+ 518 => 'ȇ',
+ 520 => 'ȉ',
+ 522 => 'ȋ',
+ 524 => 'ȍ',
+ 526 => 'ȏ',
+ 528 => 'ȑ',
+ 530 => 'ȓ',
+ 532 => 'ȕ',
+ 534 => 'ȗ',
+ 536 => 'ș',
+ 538 => 'ț',
+ 540 => 'ȝ',
+ 542 => 'ȟ',
+ 544 => 'ƞ',
+ 546 => 'ȣ',
+ 548 => 'ȥ',
+ 550 => 'ȧ',
+ 552 => 'ȩ',
+ 554 => 'ȫ',
+ 556 => 'ȭ',
+ 558 => 'ȯ',
+ 560 => 'ȱ',
+ 562 => 'ȳ',
+ 570 => 'ⱥ',
+ 571 => 'ȼ',
+ 573 => 'ƚ',
+ 574 => 'ⱦ',
+ 577 => 'ɂ',
+ 579 => 'ƀ',
+ 580 => 'ʉ',
+ 581 => 'ʌ',
+ 582 => 'ɇ',
+ 584 => 'ɉ',
+ 586 => 'ɋ',
+ 588 => 'ɍ',
+ 590 => 'ɏ',
+ 688 => 'h',
+ 689 => 'ɦ',
+ 690 => 'j',
+ 691 => 'r',
+ 692 => 'ɹ',
+ 693 => 'ɻ',
+ 694 => 'ʁ',
+ 695 => 'w',
+ 696 => 'y',
+ 736 => 'ɣ',
+ 737 => 'l',
+ 738 => 's',
+ 739 => 'x',
+ 740 => 'ʕ',
+ 832 => '̀',
+ 833 => '́',
+ 835 => '̓',
+ 836 => '̈́',
+ 837 => 'ι',
+ 880 => 'ͱ',
+ 882 => 'ͳ',
+ 884 => 'ʹ',
+ 886 => 'ͷ',
+ 895 => 'ϳ',
+ 902 => 'ά',
+ 903 => '·',
+ 904 => 'έ',
+ 905 => 'ή',
+ 906 => 'ί',
+ 908 => 'ό',
+ 910 => 'ύ',
+ 911 => 'ώ',
+ 913 => 'α',
+ 914 => 'β',
+ 915 => 'γ',
+ 916 => 'δ',
+ 917 => 'ε',
+ 918 => 'ζ',
+ 919 => 'η',
+ 920 => 'θ',
+ 921 => 'ι',
+ 922 => 'κ',
+ 923 => 'λ',
+ 924 => 'μ',
+ 925 => 'ν',
+ 926 => 'ξ',
+ 927 => 'ο',
+ 928 => 'π',
+ 929 => 'ρ',
+ 931 => 'σ',
+ 932 => 'τ',
+ 933 => 'υ',
+ 934 => 'φ',
+ 935 => 'χ',
+ 936 => 'ψ',
+ 937 => 'ω',
+ 938 => 'ϊ',
+ 939 => 'ϋ',
+ 975 => 'ϗ',
+ 976 => 'β',
+ 977 => 'θ',
+ 978 => 'υ',
+ 979 => 'ύ',
+ 980 => 'ϋ',
+ 981 => 'φ',
+ 982 => 'π',
+ 984 => 'ϙ',
+ 986 => 'ϛ',
+ 988 => 'ϝ',
+ 990 => 'ϟ',
+ 992 => 'ϡ',
+ 994 => 'ϣ',
+ 996 => 'ϥ',
+ 998 => 'ϧ',
+ 1000 => 'ϩ',
+ 1002 => 'ϫ',
+ 1004 => 'ϭ',
+ 1006 => 'ϯ',
+ 1008 => 'κ',
+ 1009 => 'ρ',
+ 1010 => 'σ',
+ 1012 => 'θ',
+ 1013 => 'ε',
+ 1015 => 'ϸ',
+ 1017 => 'σ',
+ 1018 => 'ϻ',
+ 1021 => 'ͻ',
+ 1022 => 'ͼ',
+ 1023 => 'ͽ',
+ 1024 => 'ѐ',
+ 1025 => 'ё',
+ 1026 => 'ђ',
+ 1027 => 'ѓ',
+ 1028 => 'є',
+ 1029 => 'ѕ',
+ 1030 => 'і',
+ 1031 => 'ї',
+ 1032 => 'ј',
+ 1033 => 'љ',
+ 1034 => 'њ',
+ 1035 => 'ћ',
+ 1036 => 'ќ',
+ 1037 => 'ѝ',
+ 1038 => 'ў',
+ 1039 => 'џ',
+ 1040 => 'а',
+ 1041 => 'б',
+ 1042 => 'в',
+ 1043 => 'г',
+ 1044 => 'д',
+ 1045 => 'е',
+ 1046 => 'ж',
+ 1047 => 'з',
+ 1048 => 'и',
+ 1049 => 'й',
+ 1050 => 'к',
+ 1051 => 'л',
+ 1052 => 'м',
+ 1053 => 'н',
+ 1054 => 'о',
+ 1055 => 'п',
+ 1056 => 'р',
+ 1057 => 'с',
+ 1058 => 'т',
+ 1059 => 'у',
+ 1060 => 'ф',
+ 1061 => 'х',
+ 1062 => 'ц',
+ 1063 => 'ч',
+ 1064 => 'ш',
+ 1065 => 'щ',
+ 1066 => 'ъ',
+ 1067 => 'ы',
+ 1068 => 'ь',
+ 1069 => 'э',
+ 1070 => 'ю',
+ 1071 => 'я',
+ 1120 => 'ѡ',
+ 1122 => 'ѣ',
+ 1124 => 'ѥ',
+ 1126 => 'ѧ',
+ 1128 => 'ѩ',
+ 1130 => 'ѫ',
+ 1132 => 'ѭ',
+ 1134 => 'ѯ',
+ 1136 => 'ѱ',
+ 1138 => 'ѳ',
+ 1140 => 'ѵ',
+ 1142 => 'ѷ',
+ 1144 => 'ѹ',
+ 1146 => 'ѻ',
+ 1148 => 'ѽ',
+ 1150 => 'ѿ',
+ 1152 => 'ҁ',
+ 1162 => 'ҋ',
+ 1164 => 'ҍ',
+ 1166 => 'ҏ',
+ 1168 => 'ґ',
+ 1170 => 'ғ',
+ 1172 => 'ҕ',
+ 1174 => 'җ',
+ 1176 => 'ҙ',
+ 1178 => 'қ',
+ 1180 => 'ҝ',
+ 1182 => 'ҟ',
+ 1184 => 'ҡ',
+ 1186 => 'ң',
+ 1188 => 'ҥ',
+ 1190 => 'ҧ',
+ 1192 => 'ҩ',
+ 1194 => 'ҫ',
+ 1196 => 'ҭ',
+ 1198 => 'ү',
+ 1200 => 'ұ',
+ 1202 => 'ҳ',
+ 1204 => 'ҵ',
+ 1206 => 'ҷ',
+ 1208 => 'ҹ',
+ 1210 => 'һ',
+ 1212 => 'ҽ',
+ 1214 => 'ҿ',
+ 1217 => 'ӂ',
+ 1219 => 'ӄ',
+ 1221 => 'ӆ',
+ 1223 => 'ӈ',
+ 1225 => 'ӊ',
+ 1227 => 'ӌ',
+ 1229 => 'ӎ',
+ 1232 => 'ӑ',
+ 1234 => 'ӓ',
+ 1236 => 'ӕ',
+ 1238 => 'ӗ',
+ 1240 => 'ә',
+ 1242 => 'ӛ',
+ 1244 => 'ӝ',
+ 1246 => 'ӟ',
+ 1248 => 'ӡ',
+ 1250 => 'ӣ',
+ 1252 => 'ӥ',
+ 1254 => 'ӧ',
+ 1256 => 'ө',
+ 1258 => 'ӫ',
+ 1260 => 'ӭ',
+ 1262 => 'ӯ',
+ 1264 => 'ӱ',
+ 1266 => 'ӳ',
+ 1268 => 'ӵ',
+ 1270 => 'ӷ',
+ 1272 => 'ӹ',
+ 1274 => 'ӻ',
+ 1276 => 'ӽ',
+ 1278 => 'ӿ',
+ 1280 => 'ԁ',
+ 1282 => 'ԃ',
+ 1284 => 'ԅ',
+ 1286 => 'ԇ',
+ 1288 => 'ԉ',
+ 1290 => 'ԋ',
+ 1292 => 'ԍ',
+ 1294 => 'ԏ',
+ 1296 => 'ԑ',
+ 1298 => 'ԓ',
+ 1300 => 'ԕ',
+ 1302 => 'ԗ',
+ 1304 => 'ԙ',
+ 1306 => 'ԛ',
+ 1308 => 'ԝ',
+ 1310 => 'ԟ',
+ 1312 => 'ԡ',
+ 1314 => 'ԣ',
+ 1316 => 'ԥ',
+ 1318 => 'ԧ',
+ 1320 => 'ԩ',
+ 1322 => 'ԫ',
+ 1324 => 'ԭ',
+ 1326 => 'ԯ',
+ 1329 => 'ա',
+ 1330 => 'բ',
+ 1331 => 'գ',
+ 1332 => 'դ',
+ 1333 => 'ե',
+ 1334 => 'զ',
+ 1335 => 'է',
+ 1336 => 'ը',
+ 1337 => 'թ',
+ 1338 => 'ժ',
+ 1339 => 'ի',
+ 1340 => 'լ',
+ 1341 => 'խ',
+ 1342 => 'ծ',
+ 1343 => 'կ',
+ 1344 => 'հ',
+ 1345 => 'ձ',
+ 1346 => 'ղ',
+ 1347 => 'ճ',
+ 1348 => 'մ',
+ 1349 => 'յ',
+ 1350 => 'ն',
+ 1351 => 'շ',
+ 1352 => 'ո',
+ 1353 => 'չ',
+ 1354 => 'պ',
+ 1355 => 'ջ',
+ 1356 => 'ռ',
+ 1357 => 'ս',
+ 1358 => 'վ',
+ 1359 => 'տ',
+ 1360 => 'ր',
+ 1361 => 'ց',
+ 1362 => 'ւ',
+ 1363 => 'փ',
+ 1364 => 'ք',
+ 1365 => 'օ',
+ 1366 => 'ֆ',
+ 1415 => 'եւ',
+ 1653 => 'اٴ',
+ 1654 => 'وٴ',
+ 1655 => 'ۇٴ',
+ 1656 => 'يٴ',
+ 2392 => 'क़',
+ 2393 => 'ख़',
+ 2394 => 'ग़',
+ 2395 => 'ज़',
+ 2396 => 'ड़',
+ 2397 => 'ढ़',
+ 2398 => 'फ़',
+ 2399 => 'य़',
+ 2524 => 'ড়',
+ 2525 => 'ঢ়',
+ 2527 => 'য়',
+ 2611 => 'ਲ਼',
+ 2614 => 'ਸ਼',
+ 2649 => 'ਖ਼',
+ 2650 => 'ਗ਼',
+ 2651 => 'ਜ਼',
+ 2654 => 'ਫ਼',
+ 2908 => 'ଡ଼',
+ 2909 => 'ଢ଼',
+ 3635 => 'ํา',
+ 3763 => 'ໍາ',
+ 3804 => 'ຫນ',
+ 3805 => 'ຫມ',
+ 3852 => '་',
+ 3907 => 'གྷ',
+ 3917 => 'ཌྷ',
+ 3922 => 'དྷ',
+ 3927 => 'བྷ',
+ 3932 => 'ཛྷ',
+ 3945 => 'ཀྵ',
+ 3955 => 'ཱི',
+ 3957 => 'ཱུ',
+ 3958 => 'ྲྀ',
+ 3959 => 'ྲཱྀ',
+ 3960 => 'ླྀ',
+ 3961 => 'ླཱྀ',
+ 3969 => 'ཱྀ',
+ 3987 => 'ྒྷ',
+ 3997 => 'ྜྷ',
+ 4002 => 'ྡྷ',
+ 4007 => 'ྦྷ',
+ 4012 => 'ྫྷ',
+ 4025 => 'ྐྵ',
+ 4295 => 'ⴧ',
+ 4301 => 'ⴭ',
+ 4348 => 'ნ',
+ 5112 => 'Ᏸ',
+ 5113 => 'Ᏹ',
+ 5114 => 'Ᏺ',
+ 5115 => 'Ᏻ',
+ 5116 => 'Ᏼ',
+ 5117 => 'Ᏽ',
+ 7296 => 'в',
+ 7297 => 'д',
+ 7298 => 'о',
+ 7299 => 'с',
+ 7300 => 'т',
+ 7301 => 'т',
+ 7302 => 'ъ',
+ 7303 => 'ѣ',
+ 7304 => 'ꙋ',
+ 7312 => 'ა',
+ 7313 => 'ბ',
+ 7314 => 'გ',
+ 7315 => 'დ',
+ 7316 => 'ე',
+ 7317 => 'ვ',
+ 7318 => 'ზ',
+ 7319 => 'თ',
+ 7320 => 'ი',
+ 7321 => 'კ',
+ 7322 => 'ლ',
+ 7323 => 'მ',
+ 7324 => 'ნ',
+ 7325 => 'ო',
+ 7326 => 'პ',
+ 7327 => 'ჟ',
+ 7328 => 'რ',
+ 7329 => 'ს',
+ 7330 => 'ტ',
+ 7331 => 'უ',
+ 7332 => 'ფ',
+ 7333 => 'ქ',
+ 7334 => 'ღ',
+ 7335 => 'ყ',
+ 7336 => 'შ',
+ 7337 => 'ჩ',
+ 7338 => 'ც',
+ 7339 => 'ძ',
+ 7340 => 'წ',
+ 7341 => 'ჭ',
+ 7342 => 'ხ',
+ 7343 => 'ჯ',
+ 7344 => 'ჰ',
+ 7345 => 'ჱ',
+ 7346 => 'ჲ',
+ 7347 => 'ჳ',
+ 7348 => 'ჴ',
+ 7349 => 'ჵ',
+ 7350 => 'ჶ',
+ 7351 => 'ჷ',
+ 7352 => 'ჸ',
+ 7353 => 'ჹ',
+ 7354 => 'ჺ',
+ 7357 => 'ჽ',
+ 7358 => 'ჾ',
+ 7359 => 'ჿ',
+ 7468 => 'a',
+ 7469 => 'æ',
+ 7470 => 'b',
+ 7472 => 'd',
+ 7473 => 'e',
+ 7474 => 'ǝ',
+ 7475 => 'g',
+ 7476 => 'h',
+ 7477 => 'i',
+ 7478 => 'j',
+ 7479 => 'k',
+ 7480 => 'l',
+ 7481 => 'm',
+ 7482 => 'n',
+ 7484 => 'o',
+ 7485 => 'ȣ',
+ 7486 => 'p',
+ 7487 => 'r',
+ 7488 => 't',
+ 7489 => 'u',
+ 7490 => 'w',
+ 7491 => 'a',
+ 7492 => 'ɐ',
+ 7493 => 'ɑ',
+ 7494 => 'ᴂ',
+ 7495 => 'b',
+ 7496 => 'd',
+ 7497 => 'e',
+ 7498 => 'ə',
+ 7499 => 'ɛ',
+ 7500 => 'ɜ',
+ 7501 => 'g',
+ 7503 => 'k',
+ 7504 => 'm',
+ 7505 => 'ŋ',
+ 7506 => 'o',
+ 7507 => 'ɔ',
+ 7508 => 'ᴖ',
+ 7509 => 'ᴗ',
+ 7510 => 'p',
+ 7511 => 't',
+ 7512 => 'u',
+ 7513 => 'ᴝ',
+ 7514 => 'ɯ',
+ 7515 => 'v',
+ 7516 => 'ᴥ',
+ 7517 => 'β',
+ 7518 => 'γ',
+ 7519 => 'δ',
+ 7520 => 'φ',
+ 7521 => 'χ',
+ 7522 => 'i',
+ 7523 => 'r',
+ 7524 => 'u',
+ 7525 => 'v',
+ 7526 => 'β',
+ 7527 => 'γ',
+ 7528 => 'ρ',
+ 7529 => 'φ',
+ 7530 => 'χ',
+ 7544 => 'н',
+ 7579 => 'ɒ',
+ 7580 => 'c',
+ 7581 => 'ɕ',
+ 7582 => 'ð',
+ 7583 => 'ɜ',
+ 7584 => 'f',
+ 7585 => 'ɟ',
+ 7586 => 'ɡ',
+ 7587 => 'ɥ',
+ 7588 => 'ɨ',
+ 7589 => 'ɩ',
+ 7590 => 'ɪ',
+ 7591 => 'ᵻ',
+ 7592 => 'ʝ',
+ 7593 => 'ɭ',
+ 7594 => 'ᶅ',
+ 7595 => 'ʟ',
+ 7596 => 'ɱ',
+ 7597 => 'ɰ',
+ 7598 => 'ɲ',
+ 7599 => 'ɳ',
+ 7600 => 'ɴ',
+ 7601 => 'ɵ',
+ 7602 => 'ɸ',
+ 7603 => 'ʂ',
+ 7604 => 'ʃ',
+ 7605 => 'ƫ',
+ 7606 => 'ʉ',
+ 7607 => 'ʊ',
+ 7608 => 'ᴜ',
+ 7609 => 'ʋ',
+ 7610 => 'ʌ',
+ 7611 => 'z',
+ 7612 => 'ʐ',
+ 7613 => 'ʑ',
+ 7614 => 'ʒ',
+ 7615 => 'θ',
+ 7680 => 'ḁ',
+ 7682 => 'ḃ',
+ 7684 => 'ḅ',
+ 7686 => 'ḇ',
+ 7688 => 'ḉ',
+ 7690 => 'ḋ',
+ 7692 => 'ḍ',
+ 7694 => 'ḏ',
+ 7696 => 'ḑ',
+ 7698 => 'ḓ',
+ 7700 => 'ḕ',
+ 7702 => 'ḗ',
+ 7704 => 'ḙ',
+ 7706 => 'ḛ',
+ 7708 => 'ḝ',
+ 7710 => 'ḟ',
+ 7712 => 'ḡ',
+ 7714 => 'ḣ',
+ 7716 => 'ḥ',
+ 7718 => 'ḧ',
+ 7720 => 'ḩ',
+ 7722 => 'ḫ',
+ 7724 => 'ḭ',
+ 7726 => 'ḯ',
+ 7728 => 'ḱ',
+ 7730 => 'ḳ',
+ 7732 => 'ḵ',
+ 7734 => 'ḷ',
+ 7736 => 'ḹ',
+ 7738 => 'ḻ',
+ 7740 => 'ḽ',
+ 7742 => 'ḿ',
+ 7744 => 'ṁ',
+ 7746 => 'ṃ',
+ 7748 => 'ṅ',
+ 7750 => 'ṇ',
+ 7752 => 'ṉ',
+ 7754 => 'ṋ',
+ 7756 => 'ṍ',
+ 7758 => 'ṏ',
+ 7760 => 'ṑ',
+ 7762 => 'ṓ',
+ 7764 => 'ṕ',
+ 7766 => 'ṗ',
+ 7768 => 'ṙ',
+ 7770 => 'ṛ',
+ 7772 => 'ṝ',
+ 7774 => 'ṟ',
+ 7776 => 'ṡ',
+ 7778 => 'ṣ',
+ 7780 => 'ṥ',
+ 7782 => 'ṧ',
+ 7784 => 'ṩ',
+ 7786 => 'ṫ',
+ 7788 => 'ṭ',
+ 7790 => 'ṯ',
+ 7792 => 'ṱ',
+ 7794 => 'ṳ',
+ 7796 => 'ṵ',
+ 7798 => 'ṷ',
+ 7800 => 'ṹ',
+ 7802 => 'ṻ',
+ 7804 => 'ṽ',
+ 7806 => 'ṿ',
+ 7808 => 'ẁ',
+ 7810 => 'ẃ',
+ 7812 => 'ẅ',
+ 7814 => 'ẇ',
+ 7816 => 'ẉ',
+ 7818 => 'ẋ',
+ 7820 => 'ẍ',
+ 7822 => 'ẏ',
+ 7824 => 'ẑ',
+ 7826 => 'ẓ',
+ 7828 => 'ẕ',
+ 7834 => 'aʾ',
+ 7835 => 'ṡ',
+ 7838 => 'ss',
+ 7840 => 'ạ',
+ 7842 => 'ả',
+ 7844 => 'ấ',
+ 7846 => 'ầ',
+ 7848 => 'ẩ',
+ 7850 => 'ẫ',
+ 7852 => 'ậ',
+ 7854 => 'ắ',
+ 7856 => 'ằ',
+ 7858 => 'ẳ',
+ 7860 => 'ẵ',
+ 7862 => 'ặ',
+ 7864 => 'ẹ',
+ 7866 => 'ẻ',
+ 7868 => 'ẽ',
+ 7870 => 'ế',
+ 7872 => 'ề',
+ 7874 => 'ể',
+ 7876 => 'ễ',
+ 7878 => 'ệ',
+ 7880 => 'ỉ',
+ 7882 => 'ị',
+ 7884 => 'ọ',
+ 7886 => 'ỏ',
+ 7888 => 'ố',
+ 7890 => 'ồ',
+ 7892 => 'ổ',
+ 7894 => 'ỗ',
+ 7896 => 'ộ',
+ 7898 => 'ớ',
+ 7900 => 'ờ',
+ 7902 => 'ở',
+ 7904 => 'ỡ',
+ 7906 => 'ợ',
+ 7908 => 'ụ',
+ 7910 => 'ủ',
+ 7912 => 'ứ',
+ 7914 => 'ừ',
+ 7916 => 'ử',
+ 7918 => 'ữ',
+ 7920 => 'ự',
+ 7922 => 'ỳ',
+ 7924 => 'ỵ',
+ 7926 => 'ỷ',
+ 7928 => 'ỹ',
+ 7930 => 'ỻ',
+ 7932 => 'ỽ',
+ 7934 => 'ỿ',
+ 7944 => 'ἀ',
+ 7945 => 'ἁ',
+ 7946 => 'ἂ',
+ 7947 => 'ἃ',
+ 7948 => 'ἄ',
+ 7949 => 'ἅ',
+ 7950 => 'ἆ',
+ 7951 => 'ἇ',
+ 7960 => 'ἐ',
+ 7961 => 'ἑ',
+ 7962 => 'ἒ',
+ 7963 => 'ἓ',
+ 7964 => 'ἔ',
+ 7965 => 'ἕ',
+ 7976 => 'ἠ',
+ 7977 => 'ἡ',
+ 7978 => 'ἢ',
+ 7979 => 'ἣ',
+ 7980 => 'ἤ',
+ 7981 => 'ἥ',
+ 7982 => 'ἦ',
+ 7983 => 'ἧ',
+ 7992 => 'ἰ',
+ 7993 => 'ἱ',
+ 7994 => 'ἲ',
+ 7995 => 'ἳ',
+ 7996 => 'ἴ',
+ 7997 => 'ἵ',
+ 7998 => 'ἶ',
+ 7999 => 'ἷ',
+ 8008 => 'ὀ',
+ 8009 => 'ὁ',
+ 8010 => 'ὂ',
+ 8011 => 'ὃ',
+ 8012 => 'ὄ',
+ 8013 => 'ὅ',
+ 8025 => 'ὑ',
+ 8027 => 'ὓ',
+ 8029 => 'ὕ',
+ 8031 => 'ὗ',
+ 8040 => 'ὠ',
+ 8041 => 'ὡ',
+ 8042 => 'ὢ',
+ 8043 => 'ὣ',
+ 8044 => 'ὤ',
+ 8045 => 'ὥ',
+ 8046 => 'ὦ',
+ 8047 => 'ὧ',
+ 8049 => 'ά',
+ 8051 => 'έ',
+ 8053 => 'ή',
+ 8055 => 'ί',
+ 8057 => 'ό',
+ 8059 => 'ύ',
+ 8061 => 'ώ',
+ 8064 => 'ἀι',
+ 8065 => 'ἁι',
+ 8066 => 'ἂι',
+ 8067 => 'ἃι',
+ 8068 => 'ἄι',
+ 8069 => 'ἅι',
+ 8070 => 'ἆι',
+ 8071 => 'ἇι',
+ 8072 => 'ἀι',
+ 8073 => 'ἁι',
+ 8074 => 'ἂι',
+ 8075 => 'ἃι',
+ 8076 => 'ἄι',
+ 8077 => 'ἅι',
+ 8078 => 'ἆι',
+ 8079 => 'ἇι',
+ 8080 => 'ἠι',
+ 8081 => 'ἡι',
+ 8082 => 'ἢι',
+ 8083 => 'ἣι',
+ 8084 => 'ἤι',
+ 8085 => 'ἥι',
+ 8086 => 'ἦι',
+ 8087 => 'ἧι',
+ 8088 => 'ἠι',
+ 8089 => 'ἡι',
+ 8090 => 'ἢι',
+ 8091 => 'ἣι',
+ 8092 => 'ἤι',
+ 8093 => 'ἥι',
+ 8094 => 'ἦι',
+ 8095 => 'ἧι',
+ 8096 => 'ὠι',
+ 8097 => 'ὡι',
+ 8098 => 'ὢι',
+ 8099 => 'ὣι',
+ 8100 => 'ὤι',
+ 8101 => 'ὥι',
+ 8102 => 'ὦι',
+ 8103 => 'ὧι',
+ 8104 => 'ὠι',
+ 8105 => 'ὡι',
+ 8106 => 'ὢι',
+ 8107 => 'ὣι',
+ 8108 => 'ὤι',
+ 8109 => 'ὥι',
+ 8110 => 'ὦι',
+ 8111 => 'ὧι',
+ 8114 => 'ὰι',
+ 8115 => 'αι',
+ 8116 => 'άι',
+ 8119 => 'ᾶι',
+ 8120 => 'ᾰ',
+ 8121 => 'ᾱ',
+ 8122 => 'ὰ',
+ 8123 => 'ά',
+ 8124 => 'αι',
+ 8126 => 'ι',
+ 8130 => 'ὴι',
+ 8131 => 'ηι',
+ 8132 => 'ήι',
+ 8135 => 'ῆι',
+ 8136 => 'ὲ',
+ 8137 => 'έ',
+ 8138 => 'ὴ',
+ 8139 => 'ή',
+ 8140 => 'ηι',
+ 8147 => 'ΐ',
+ 8152 => 'ῐ',
+ 8153 => 'ῑ',
+ 8154 => 'ὶ',
+ 8155 => 'ί',
+ 8163 => 'ΰ',
+ 8168 => 'ῠ',
+ 8169 => 'ῡ',
+ 8170 => 'ὺ',
+ 8171 => 'ύ',
+ 8172 => 'ῥ',
+ 8178 => 'ὼι',
+ 8179 => 'ωι',
+ 8180 => 'ώι',
+ 8183 => 'ῶι',
+ 8184 => 'ὸ',
+ 8185 => 'ό',
+ 8186 => 'ὼ',
+ 8187 => 'ώ',
+ 8188 => 'ωι',
+ 8209 => '‐',
+ 8243 => '′′',
+ 8244 => '′′′',
+ 8246 => '‵‵',
+ 8247 => '‵‵‵',
+ 8279 => '′′′′',
+ 8304 => '0',
+ 8305 => 'i',
+ 8308 => '4',
+ 8309 => '5',
+ 8310 => '6',
+ 8311 => '7',
+ 8312 => '8',
+ 8313 => '9',
+ 8315 => '−',
+ 8319 => 'n',
+ 8320 => '0',
+ 8321 => '1',
+ 8322 => '2',
+ 8323 => '3',
+ 8324 => '4',
+ 8325 => '5',
+ 8326 => '6',
+ 8327 => '7',
+ 8328 => '8',
+ 8329 => '9',
+ 8331 => '−',
+ 8336 => 'a',
+ 8337 => 'e',
+ 8338 => 'o',
+ 8339 => 'x',
+ 8340 => 'ə',
+ 8341 => 'h',
+ 8342 => 'k',
+ 8343 => 'l',
+ 8344 => 'm',
+ 8345 => 'n',
+ 8346 => 'p',
+ 8347 => 's',
+ 8348 => 't',
+ 8360 => 'rs',
+ 8450 => 'c',
+ 8451 => '°c',
+ 8455 => 'ɛ',
+ 8457 => '°f',
+ 8458 => 'g',
+ 8459 => 'h',
+ 8460 => 'h',
+ 8461 => 'h',
+ 8462 => 'h',
+ 8463 => 'ħ',
+ 8464 => 'i',
+ 8465 => 'i',
+ 8466 => 'l',
+ 8467 => 'l',
+ 8469 => 'n',
+ 8470 => 'no',
+ 8473 => 'p',
+ 8474 => 'q',
+ 8475 => 'r',
+ 8476 => 'r',
+ 8477 => 'r',
+ 8480 => 'sm',
+ 8481 => 'tel',
+ 8482 => 'tm',
+ 8484 => 'z',
+ 8486 => 'ω',
+ 8488 => 'z',
+ 8490 => 'k',
+ 8491 => 'å',
+ 8492 => 'b',
+ 8493 => 'c',
+ 8495 => 'e',
+ 8496 => 'e',
+ 8497 => 'f',
+ 8499 => 'm',
+ 8500 => 'o',
+ 8501 => 'א',
+ 8502 => 'ב',
+ 8503 => 'ג',
+ 8504 => 'ד',
+ 8505 => 'i',
+ 8507 => 'fax',
+ 8508 => 'π',
+ 8509 => 'γ',
+ 8510 => 'γ',
+ 8511 => 'π',
+ 8512 => '∑',
+ 8517 => 'd',
+ 8518 => 'd',
+ 8519 => 'e',
+ 8520 => 'i',
+ 8521 => 'j',
+ 8528 => '1⁄7',
+ 8529 => '1⁄9',
+ 8530 => '1⁄10',
+ 8531 => '1⁄3',
+ 8532 => '2⁄3',
+ 8533 => '1⁄5',
+ 8534 => '2⁄5',
+ 8535 => '3⁄5',
+ 8536 => '4⁄5',
+ 8537 => '1⁄6',
+ 8538 => '5⁄6',
+ 8539 => '1⁄8',
+ 8540 => '3⁄8',
+ 8541 => '5⁄8',
+ 8542 => '7⁄8',
+ 8543 => '1⁄',
+ 8544 => 'i',
+ 8545 => 'ii',
+ 8546 => 'iii',
+ 8547 => 'iv',
+ 8548 => 'v',
+ 8549 => 'vi',
+ 8550 => 'vii',
+ 8551 => 'viii',
+ 8552 => 'ix',
+ 8553 => 'x',
+ 8554 => 'xi',
+ 8555 => 'xii',
+ 8556 => 'l',
+ 8557 => 'c',
+ 8558 => 'd',
+ 8559 => 'm',
+ 8560 => 'i',
+ 8561 => 'ii',
+ 8562 => 'iii',
+ 8563 => 'iv',
+ 8564 => 'v',
+ 8565 => 'vi',
+ 8566 => 'vii',
+ 8567 => 'viii',
+ 8568 => 'ix',
+ 8569 => 'x',
+ 8570 => 'xi',
+ 8571 => 'xii',
+ 8572 => 'l',
+ 8573 => 'c',
+ 8574 => 'd',
+ 8575 => 'm',
+ 8585 => '0⁄3',
+ 8748 => '∫∫',
+ 8749 => '∫∫∫',
+ 8751 => '∮∮',
+ 8752 => '∮∮∮',
+ 9001 => '〈',
+ 9002 => '〉',
+ 9312 => '1',
+ 9313 => '2',
+ 9314 => '3',
+ 9315 => '4',
+ 9316 => '5',
+ 9317 => '6',
+ 9318 => '7',
+ 9319 => '8',
+ 9320 => '9',
+ 9321 => '10',
+ 9322 => '11',
+ 9323 => '12',
+ 9324 => '13',
+ 9325 => '14',
+ 9326 => '15',
+ 9327 => '16',
+ 9328 => '17',
+ 9329 => '18',
+ 9330 => '19',
+ 9331 => '20',
+ 9398 => 'a',
+ 9399 => 'b',
+ 9400 => 'c',
+ 9401 => 'd',
+ 9402 => 'e',
+ 9403 => 'f',
+ 9404 => 'g',
+ 9405 => 'h',
+ 9406 => 'i',
+ 9407 => 'j',
+ 9408 => 'k',
+ 9409 => 'l',
+ 9410 => 'm',
+ 9411 => 'n',
+ 9412 => 'o',
+ 9413 => 'p',
+ 9414 => 'q',
+ 9415 => 'r',
+ 9416 => 's',
+ 9417 => 't',
+ 9418 => 'u',
+ 9419 => 'v',
+ 9420 => 'w',
+ 9421 => 'x',
+ 9422 => 'y',
+ 9423 => 'z',
+ 9424 => 'a',
+ 9425 => 'b',
+ 9426 => 'c',
+ 9427 => 'd',
+ 9428 => 'e',
+ 9429 => 'f',
+ 9430 => 'g',
+ 9431 => 'h',
+ 9432 => 'i',
+ 9433 => 'j',
+ 9434 => 'k',
+ 9435 => 'l',
+ 9436 => 'm',
+ 9437 => 'n',
+ 9438 => 'o',
+ 9439 => 'p',
+ 9440 => 'q',
+ 9441 => 'r',
+ 9442 => 's',
+ 9443 => 't',
+ 9444 => 'u',
+ 9445 => 'v',
+ 9446 => 'w',
+ 9447 => 'x',
+ 9448 => 'y',
+ 9449 => 'z',
+ 9450 => '0',
+ 10764 => '∫∫∫∫',
+ 10972 => '⫝̸',
+ 11264 => 'ⰰ',
+ 11265 => 'ⰱ',
+ 11266 => 'ⰲ',
+ 11267 => 'ⰳ',
+ 11268 => 'ⰴ',
+ 11269 => 'ⰵ',
+ 11270 => 'ⰶ',
+ 11271 => 'ⰷ',
+ 11272 => 'ⰸ',
+ 11273 => 'ⰹ',
+ 11274 => 'ⰺ',
+ 11275 => 'ⰻ',
+ 11276 => 'ⰼ',
+ 11277 => 'ⰽ',
+ 11278 => 'ⰾ',
+ 11279 => 'ⰿ',
+ 11280 => 'ⱀ',
+ 11281 => 'ⱁ',
+ 11282 => 'ⱂ',
+ 11283 => 'ⱃ',
+ 11284 => 'ⱄ',
+ 11285 => 'ⱅ',
+ 11286 => 'ⱆ',
+ 11287 => 'ⱇ',
+ 11288 => 'ⱈ',
+ 11289 => 'ⱉ',
+ 11290 => 'ⱊ',
+ 11291 => 'ⱋ',
+ 11292 => 'ⱌ',
+ 11293 => 'ⱍ',
+ 11294 => 'ⱎ',
+ 11295 => 'ⱏ',
+ 11296 => 'ⱐ',
+ 11297 => 'ⱑ',
+ 11298 => 'ⱒ',
+ 11299 => 'ⱓ',
+ 11300 => 'ⱔ',
+ 11301 => 'ⱕ',
+ 11302 => 'ⱖ',
+ 11303 => 'ⱗ',
+ 11304 => 'ⱘ',
+ 11305 => 'ⱙ',
+ 11306 => 'ⱚ',
+ 11307 => 'ⱛ',
+ 11308 => 'ⱜ',
+ 11309 => 'ⱝ',
+ 11310 => 'ⱞ',
+ 11360 => 'ⱡ',
+ 11362 => 'ɫ',
+ 11363 => 'ᵽ',
+ 11364 => 'ɽ',
+ 11367 => 'ⱨ',
+ 11369 => 'ⱪ',
+ 11371 => 'ⱬ',
+ 11373 => 'ɑ',
+ 11374 => 'ɱ',
+ 11375 => 'ɐ',
+ 11376 => 'ɒ',
+ 11378 => 'ⱳ',
+ 11381 => 'ⱶ',
+ 11388 => 'j',
+ 11389 => 'v',
+ 11390 => 'ȿ',
+ 11391 => 'ɀ',
+ 11392 => 'ⲁ',
+ 11394 => 'ⲃ',
+ 11396 => 'ⲅ',
+ 11398 => 'ⲇ',
+ 11400 => 'ⲉ',
+ 11402 => 'ⲋ',
+ 11404 => 'ⲍ',
+ 11406 => 'ⲏ',
+ 11408 => 'ⲑ',
+ 11410 => 'ⲓ',
+ 11412 => 'ⲕ',
+ 11414 => 'ⲗ',
+ 11416 => 'ⲙ',
+ 11418 => 'ⲛ',
+ 11420 => 'ⲝ',
+ 11422 => 'ⲟ',
+ 11424 => 'ⲡ',
+ 11426 => 'ⲣ',
+ 11428 => 'ⲥ',
+ 11430 => 'ⲧ',
+ 11432 => 'ⲩ',
+ 11434 => 'ⲫ',
+ 11436 => 'ⲭ',
+ 11438 => 'ⲯ',
+ 11440 => 'ⲱ',
+ 11442 => 'ⲳ',
+ 11444 => 'ⲵ',
+ 11446 => 'ⲷ',
+ 11448 => 'ⲹ',
+ 11450 => 'ⲻ',
+ 11452 => 'ⲽ',
+ 11454 => 'ⲿ',
+ 11456 => 'ⳁ',
+ 11458 => 'ⳃ',
+ 11460 => 'ⳅ',
+ 11462 => 'ⳇ',
+ 11464 => 'ⳉ',
+ 11466 => 'ⳋ',
+ 11468 => 'ⳍ',
+ 11470 => 'ⳏ',
+ 11472 => 'ⳑ',
+ 11474 => 'ⳓ',
+ 11476 => 'ⳕ',
+ 11478 => 'ⳗ',
+ 11480 => 'ⳙ',
+ 11482 => 'ⳛ',
+ 11484 => 'ⳝ',
+ 11486 => 'ⳟ',
+ 11488 => 'ⳡ',
+ 11490 => 'ⳣ',
+ 11499 => 'ⳬ',
+ 11501 => 'ⳮ',
+ 11506 => 'ⳳ',
+ 11631 => 'ⵡ',
+ 11935 => '母',
+ 12019 => '龟',
+ 12032 => '一',
+ 12033 => '丨',
+ 12034 => '丶',
+ 12035 => '丿',
+ 12036 => '乙',
+ 12037 => '亅',
+ 12038 => '二',
+ 12039 => '亠',
+ 12040 => '人',
+ 12041 => '儿',
+ 12042 => '入',
+ 12043 => '八',
+ 12044 => '冂',
+ 12045 => '冖',
+ 12046 => '冫',
+ 12047 => '几',
+ 12048 => '凵',
+ 12049 => '刀',
+ 12050 => '力',
+ 12051 => '勹',
+ 12052 => '匕',
+ 12053 => '匚',
+ 12054 => '匸',
+ 12055 => '十',
+ 12056 => '卜',
+ 12057 => '卩',
+ 12058 => '厂',
+ 12059 => '厶',
+ 12060 => '又',
+ 12061 => '口',
+ 12062 => '囗',
+ 12063 => '土',
+ 12064 => '士',
+ 12065 => '夂',
+ 12066 => '夊',
+ 12067 => '夕',
+ 12068 => '大',
+ 12069 => '女',
+ 12070 => '子',
+ 12071 => '宀',
+ 12072 => '寸',
+ 12073 => '小',
+ 12074 => '尢',
+ 12075 => '尸',
+ 12076 => '屮',
+ 12077 => '山',
+ 12078 => '巛',
+ 12079 => '工',
+ 12080 => '己',
+ 12081 => '巾',
+ 12082 => '干',
+ 12083 => '幺',
+ 12084 => '广',
+ 12085 => '廴',
+ 12086 => '廾',
+ 12087 => '弋',
+ 12088 => '弓',
+ 12089 => '彐',
+ 12090 => '彡',
+ 12091 => '彳',
+ 12092 => '心',
+ 12093 => '戈',
+ 12094 => '戶',
+ 12095 => '手',
+ 12096 => '支',
+ 12097 => '攴',
+ 12098 => '文',
+ 12099 => '斗',
+ 12100 => '斤',
+ 12101 => '方',
+ 12102 => '无',
+ 12103 => '日',
+ 12104 => '曰',
+ 12105 => '月',
+ 12106 => '木',
+ 12107 => '欠',
+ 12108 => '止',
+ 12109 => '歹',
+ 12110 => '殳',
+ 12111 => '毋',
+ 12112 => '比',
+ 12113 => '毛',
+ 12114 => '氏',
+ 12115 => '气',
+ 12116 => '水',
+ 12117 => '火',
+ 12118 => '爪',
+ 12119 => '父',
+ 12120 => '爻',
+ 12121 => '爿',
+ 12122 => '片',
+ 12123 => '牙',
+ 12124 => '牛',
+ 12125 => '犬',
+ 12126 => '玄',
+ 12127 => '玉',
+ 12128 => '瓜',
+ 12129 => '瓦',
+ 12130 => '甘',
+ 12131 => '生',
+ 12132 => '用',
+ 12133 => '田',
+ 12134 => '疋',
+ 12135 => '疒',
+ 12136 => '癶',
+ 12137 => '白',
+ 12138 => '皮',
+ 12139 => '皿',
+ 12140 => '目',
+ 12141 => '矛',
+ 12142 => '矢',
+ 12143 => '石',
+ 12144 => '示',
+ 12145 => '禸',
+ 12146 => '禾',
+ 12147 => '穴',
+ 12148 => '立',
+ 12149 => '竹',
+ 12150 => '米',
+ 12151 => '糸',
+ 12152 => '缶',
+ 12153 => '网',
+ 12154 => '羊',
+ 12155 => '羽',
+ 12156 => '老',
+ 12157 => '而',
+ 12158 => '耒',
+ 12159 => '耳',
+ 12160 => '聿',
+ 12161 => '肉',
+ 12162 => '臣',
+ 12163 => '自',
+ 12164 => '至',
+ 12165 => '臼',
+ 12166 => '舌',
+ 12167 => '舛',
+ 12168 => '舟',
+ 12169 => '艮',
+ 12170 => '色',
+ 12171 => '艸',
+ 12172 => '虍',
+ 12173 => '虫',
+ 12174 => '血',
+ 12175 => '行',
+ 12176 => '衣',
+ 12177 => '襾',
+ 12178 => '見',
+ 12179 => '角',
+ 12180 => '言',
+ 12181 => '谷',
+ 12182 => '豆',
+ 12183 => '豕',
+ 12184 => '豸',
+ 12185 => '貝',
+ 12186 => '赤',
+ 12187 => '走',
+ 12188 => '足',
+ 12189 => '身',
+ 12190 => '車',
+ 12191 => '辛',
+ 12192 => '辰',
+ 12193 => '辵',
+ 12194 => '邑',
+ 12195 => '酉',
+ 12196 => '釆',
+ 12197 => '里',
+ 12198 => '金',
+ 12199 => '長',
+ 12200 => '門',
+ 12201 => '阜',
+ 12202 => '隶',
+ 12203 => '隹',
+ 12204 => '雨',
+ 12205 => '靑',
+ 12206 => '非',
+ 12207 => '面',
+ 12208 => '革',
+ 12209 => '韋',
+ 12210 => '韭',
+ 12211 => '音',
+ 12212 => '頁',
+ 12213 => '風',
+ 12214 => '飛',
+ 12215 => '食',
+ 12216 => '首',
+ 12217 => '香',
+ 12218 => '馬',
+ 12219 => '骨',
+ 12220 => '高',
+ 12221 => '髟',
+ 12222 => '鬥',
+ 12223 => '鬯',
+ 12224 => '鬲',
+ 12225 => '鬼',
+ 12226 => '魚',
+ 12227 => '鳥',
+ 12228 => '鹵',
+ 12229 => '鹿',
+ 12230 => '麥',
+ 12231 => '麻',
+ 12232 => '黃',
+ 12233 => '黍',
+ 12234 => '黑',
+ 12235 => '黹',
+ 12236 => '黽',
+ 12237 => '鼎',
+ 12238 => '鼓',
+ 12239 => '鼠',
+ 12240 => '鼻',
+ 12241 => '齊',
+ 12242 => '齒',
+ 12243 => '龍',
+ 12244 => '龜',
+ 12245 => '龠',
+ 12290 => '.',
+ 12342 => '〒',
+ 12344 => '十',
+ 12345 => '卄',
+ 12346 => '卅',
+ 12447 => 'より',
+ 12543 => 'コト',
+ 12593 => 'ᄀ',
+ 12594 => 'ᄁ',
+ 12595 => 'ᆪ',
+ 12596 => 'ᄂ',
+ 12597 => 'ᆬ',
+ 12598 => 'ᆭ',
+ 12599 => 'ᄃ',
+ 12600 => 'ᄄ',
+ 12601 => 'ᄅ',
+ 12602 => 'ᆰ',
+ 12603 => 'ᆱ',
+ 12604 => 'ᆲ',
+ 12605 => 'ᆳ',
+ 12606 => 'ᆴ',
+ 12607 => 'ᆵ',
+ 12608 => 'ᄚ',
+ 12609 => 'ᄆ',
+ 12610 => 'ᄇ',
+ 12611 => 'ᄈ',
+ 12612 => 'ᄡ',
+ 12613 => 'ᄉ',
+ 12614 => 'ᄊ',
+ 12615 => 'ᄋ',
+ 12616 => 'ᄌ',
+ 12617 => 'ᄍ',
+ 12618 => 'ᄎ',
+ 12619 => 'ᄏ',
+ 12620 => 'ᄐ',
+ 12621 => 'ᄑ',
+ 12622 => 'ᄒ',
+ 12623 => 'ᅡ',
+ 12624 => 'ᅢ',
+ 12625 => 'ᅣ',
+ 12626 => 'ᅤ',
+ 12627 => 'ᅥ',
+ 12628 => 'ᅦ',
+ 12629 => 'ᅧ',
+ 12630 => 'ᅨ',
+ 12631 => 'ᅩ',
+ 12632 => 'ᅪ',
+ 12633 => 'ᅫ',
+ 12634 => 'ᅬ',
+ 12635 => 'ᅭ',
+ 12636 => 'ᅮ',
+ 12637 => 'ᅯ',
+ 12638 => 'ᅰ',
+ 12639 => 'ᅱ',
+ 12640 => 'ᅲ',
+ 12641 => 'ᅳ',
+ 12642 => 'ᅴ',
+ 12643 => 'ᅵ',
+ 12645 => 'ᄔ',
+ 12646 => 'ᄕ',
+ 12647 => 'ᇇ',
+ 12648 => 'ᇈ',
+ 12649 => 'ᇌ',
+ 12650 => 'ᇎ',
+ 12651 => 'ᇓ',
+ 12652 => 'ᇗ',
+ 12653 => 'ᇙ',
+ 12654 => 'ᄜ',
+ 12655 => 'ᇝ',
+ 12656 => 'ᇟ',
+ 12657 => 'ᄝ',
+ 12658 => 'ᄞ',
+ 12659 => 'ᄠ',
+ 12660 => 'ᄢ',
+ 12661 => 'ᄣ',
+ 12662 => 'ᄧ',
+ 12663 => 'ᄩ',
+ 12664 => 'ᄫ',
+ 12665 => 'ᄬ',
+ 12666 => 'ᄭ',
+ 12667 => 'ᄮ',
+ 12668 => 'ᄯ',
+ 12669 => 'ᄲ',
+ 12670 => 'ᄶ',
+ 12671 => 'ᅀ',
+ 12672 => 'ᅇ',
+ 12673 => 'ᅌ',
+ 12674 => 'ᇱ',
+ 12675 => 'ᇲ',
+ 12676 => 'ᅗ',
+ 12677 => 'ᅘ',
+ 12678 => 'ᅙ',
+ 12679 => 'ᆄ',
+ 12680 => 'ᆅ',
+ 12681 => 'ᆈ',
+ 12682 => 'ᆑ',
+ 12683 => 'ᆒ',
+ 12684 => 'ᆔ',
+ 12685 => 'ᆞ',
+ 12686 => 'ᆡ',
+ 12690 => '一',
+ 12691 => '二',
+ 12692 => '三',
+ 12693 => '四',
+ 12694 => '上',
+ 12695 => '中',
+ 12696 => '下',
+ 12697 => '甲',
+ 12698 => '乙',
+ 12699 => '丙',
+ 12700 => '丁',
+ 12701 => '天',
+ 12702 => '地',
+ 12703 => '人',
+ 12868 => '問',
+ 12869 => '幼',
+ 12870 => '文',
+ 12871 => '箏',
+ 12880 => 'pte',
+ 12881 => '21',
+ 12882 => '22',
+ 12883 => '23',
+ 12884 => '24',
+ 12885 => '25',
+ 12886 => '26',
+ 12887 => '27',
+ 12888 => '28',
+ 12889 => '29',
+ 12890 => '30',
+ 12891 => '31',
+ 12892 => '32',
+ 12893 => '33',
+ 12894 => '34',
+ 12895 => '35',
+ 12896 => 'ᄀ',
+ 12897 => 'ᄂ',
+ 12898 => 'ᄃ',
+ 12899 => 'ᄅ',
+ 12900 => 'ᄆ',
+ 12901 => 'ᄇ',
+ 12902 => 'ᄉ',
+ 12903 => 'ᄋ',
+ 12904 => 'ᄌ',
+ 12905 => 'ᄎ',
+ 12906 => 'ᄏ',
+ 12907 => 'ᄐ',
+ 12908 => 'ᄑ',
+ 12909 => 'ᄒ',
+ 12910 => '가',
+ 12911 => '나',
+ 12912 => '다',
+ 12913 => '라',
+ 12914 => '마',
+ 12915 => '바',
+ 12916 => '사',
+ 12917 => '아',
+ 12918 => '자',
+ 12919 => '차',
+ 12920 => '카',
+ 12921 => '타',
+ 12922 => '파',
+ 12923 => '하',
+ 12924 => '참고',
+ 12925 => '주의',
+ 12926 => '우',
+ 12928 => '一',
+ 12929 => '二',
+ 12930 => '三',
+ 12931 => '四',
+ 12932 => '五',
+ 12933 => '六',
+ 12934 => '七',
+ 12935 => '八',
+ 12936 => '九',
+ 12937 => '十',
+ 12938 => '月',
+ 12939 => '火',
+ 12940 => '水',
+ 12941 => '木',
+ 12942 => '金',
+ 12943 => '土',
+ 12944 => '日',
+ 12945 => '株',
+ 12946 => '有',
+ 12947 => '社',
+ 12948 => '名',
+ 12949 => '特',
+ 12950 => '財',
+ 12951 => '祝',
+ 12952 => '労',
+ 12953 => '秘',
+ 12954 => '男',
+ 12955 => '女',
+ 12956 => '適',
+ 12957 => '優',
+ 12958 => '印',
+ 12959 => '注',
+ 12960 => '項',
+ 12961 => '休',
+ 12962 => '写',
+ 12963 => '正',
+ 12964 => '上',
+ 12965 => '中',
+ 12966 => '下',
+ 12967 => '左',
+ 12968 => '右',
+ 12969 => '医',
+ 12970 => '宗',
+ 12971 => '学',
+ 12972 => '監',
+ 12973 => '企',
+ 12974 => '資',
+ 12975 => '協',
+ 12976 => '夜',
+ 12977 => '36',
+ 12978 => '37',
+ 12979 => '38',
+ 12980 => '39',
+ 12981 => '40',
+ 12982 => '41',
+ 12983 => '42',
+ 12984 => '43',
+ 12985 => '44',
+ 12986 => '45',
+ 12987 => '46',
+ 12988 => '47',
+ 12989 => '48',
+ 12990 => '49',
+ 12991 => '50',
+ 12992 => '1月',
+ 12993 => '2月',
+ 12994 => '3月',
+ 12995 => '4月',
+ 12996 => '5月',
+ 12997 => '6月',
+ 12998 => '7月',
+ 12999 => '8月',
+ 13000 => '9月',
+ 13001 => '10月',
+ 13002 => '11月',
+ 13003 => '12月',
+ 13004 => 'hg',
+ 13005 => 'erg',
+ 13006 => 'ev',
+ 13007 => 'ltd',
+ 13008 => 'ア',
+ 13009 => 'イ',
+ 13010 => 'ウ',
+ 13011 => 'エ',
+ 13012 => 'オ',
+ 13013 => 'カ',
+ 13014 => 'キ',
+ 13015 => 'ク',
+ 13016 => 'ケ',
+ 13017 => 'コ',
+ 13018 => 'サ',
+ 13019 => 'シ',
+ 13020 => 'ス',
+ 13021 => 'セ',
+ 13022 => 'ソ',
+ 13023 => 'タ',
+ 13024 => 'チ',
+ 13025 => 'ツ',
+ 13026 => 'テ',
+ 13027 => 'ト',
+ 13028 => 'ナ',
+ 13029 => 'ニ',
+ 13030 => 'ヌ',
+ 13031 => 'ネ',
+ 13032 => 'ノ',
+ 13033 => 'ハ',
+ 13034 => 'ヒ',
+ 13035 => 'フ',
+ 13036 => 'ヘ',
+ 13037 => 'ホ',
+ 13038 => 'マ',
+ 13039 => 'ミ',
+ 13040 => 'ム',
+ 13041 => 'メ',
+ 13042 => 'モ',
+ 13043 => 'ヤ',
+ 13044 => 'ユ',
+ 13045 => 'ヨ',
+ 13046 => 'ラ',
+ 13047 => 'リ',
+ 13048 => 'ル',
+ 13049 => 'レ',
+ 13050 => 'ロ',
+ 13051 => 'ワ',
+ 13052 => 'ヰ',
+ 13053 => 'ヱ',
+ 13054 => 'ヲ',
+ 13055 => '令和',
+ 13056 => 'アパート',
+ 13057 => 'アルファ',
+ 13058 => 'アンペア',
+ 13059 => 'アール',
+ 13060 => 'イニング',
+ 13061 => 'インチ',
+ 13062 => 'ウォン',
+ 13063 => 'エスクード',
+ 13064 => 'エーカー',
+ 13065 => 'オンス',
+ 13066 => 'オーム',
+ 13067 => 'カイリ',
+ 13068 => 'カラット',
+ 13069 => 'カロリー',
+ 13070 => 'ガロン',
+ 13071 => 'ガンマ',
+ 13072 => 'ギガ',
+ 13073 => 'ギニー',
+ 13074 => 'キュリー',
+ 13075 => 'ギルダー',
+ 13076 => 'キロ',
+ 13077 => 'キログラム',
+ 13078 => 'キロメートル',
+ 13079 => 'キロワット',
+ 13080 => 'グラム',
+ 13081 => 'グラムトン',
+ 13082 => 'クルゼイロ',
+ 13083 => 'クローネ',
+ 13084 => 'ケース',
+ 13085 => 'コルナ',
+ 13086 => 'コーポ',
+ 13087 => 'サイクル',
+ 13088 => 'サンチーム',
+ 13089 => 'シリング',
+ 13090 => 'センチ',
+ 13091 => 'セント',
+ 13092 => 'ダース',
+ 13093 => 'デシ',
+ 13094 => 'ドル',
+ 13095 => 'トン',
+ 13096 => 'ナノ',
+ 13097 => 'ノット',
+ 13098 => 'ハイツ',
+ 13099 => 'パーセント',
+ 13100 => 'パーツ',
+ 13101 => 'バーレル',
+ 13102 => 'ピアストル',
+ 13103 => 'ピクル',
+ 13104 => 'ピコ',
+ 13105 => 'ビル',
+ 13106 => 'ファラッド',
+ 13107 => 'フィート',
+ 13108 => 'ブッシェル',
+ 13109 => 'フラン',
+ 13110 => 'ヘクタール',
+ 13111 => 'ペソ',
+ 13112 => 'ペニヒ',
+ 13113 => 'ヘルツ',
+ 13114 => 'ペンス',
+ 13115 => 'ページ',
+ 13116 => 'ベータ',
+ 13117 => 'ポイント',
+ 13118 => 'ボルト',
+ 13119 => 'ホン',
+ 13120 => 'ポンド',
+ 13121 => 'ホール',
+ 13122 => 'ホーン',
+ 13123 => 'マイクロ',
+ 13124 => 'マイル',
+ 13125 => 'マッハ',
+ 13126 => 'マルク',
+ 13127 => 'マンション',
+ 13128 => 'ミクロン',
+ 13129 => 'ミリ',
+ 13130 => 'ミリバール',
+ 13131 => 'メガ',
+ 13132 => 'メガトン',
+ 13133 => 'メートル',
+ 13134 => 'ヤード',
+ 13135 => 'ヤール',
+ 13136 => 'ユアン',
+ 13137 => 'リットル',
+ 13138 => 'リラ',
+ 13139 => 'ルピー',
+ 13140 => 'ルーブル',
+ 13141 => 'レム',
+ 13142 => 'レントゲン',
+ 13143 => 'ワット',
+ 13144 => '0点',
+ 13145 => '1点',
+ 13146 => '2点',
+ 13147 => '3点',
+ 13148 => '4点',
+ 13149 => '5点',
+ 13150 => '6点',
+ 13151 => '7点',
+ 13152 => '8点',
+ 13153 => '9点',
+ 13154 => '10点',
+ 13155 => '11点',
+ 13156 => '12点',
+ 13157 => '13点',
+ 13158 => '14点',
+ 13159 => '15点',
+ 13160 => '16点',
+ 13161 => '17点',
+ 13162 => '18点',
+ 13163 => '19点',
+ 13164 => '20点',
+ 13165 => '21点',
+ 13166 => '22点',
+ 13167 => '23点',
+ 13168 => '24点',
+ 13169 => 'hpa',
+ 13170 => 'da',
+ 13171 => 'au',
+ 13172 => 'bar',
+ 13173 => 'ov',
+ 13174 => 'pc',
+ 13175 => 'dm',
+ 13176 => 'dm2',
+ 13177 => 'dm3',
+ 13178 => 'iu',
+ 13179 => '平成',
+ 13180 => '昭和',
+ 13181 => '大正',
+ 13182 => '明治',
+ 13183 => '株式会社',
+ 13184 => 'pa',
+ 13185 => 'na',
+ 13186 => 'μa',
+ 13187 => 'ma',
+ 13188 => 'ka',
+ 13189 => 'kb',
+ 13190 => 'mb',
+ 13191 => 'gb',
+ 13192 => 'cal',
+ 13193 => 'kcal',
+ 13194 => 'pf',
+ 13195 => 'nf',
+ 13196 => 'μf',
+ 13197 => 'μg',
+ 13198 => 'mg',
+ 13199 => 'kg',
+ 13200 => 'hz',
+ 13201 => 'khz',
+ 13202 => 'mhz',
+ 13203 => 'ghz',
+ 13204 => 'thz',
+ 13205 => 'μl',
+ 13206 => 'ml',
+ 13207 => 'dl',
+ 13208 => 'kl',
+ 13209 => 'fm',
+ 13210 => 'nm',
+ 13211 => 'μm',
+ 13212 => 'mm',
+ 13213 => 'cm',
+ 13214 => 'km',
+ 13215 => 'mm2',
+ 13216 => 'cm2',
+ 13217 => 'm2',
+ 13218 => 'km2',
+ 13219 => 'mm3',
+ 13220 => 'cm3',
+ 13221 => 'm3',
+ 13222 => 'km3',
+ 13223 => 'm∕s',
+ 13224 => 'm∕s2',
+ 13225 => 'pa',
+ 13226 => 'kpa',
+ 13227 => 'mpa',
+ 13228 => 'gpa',
+ 13229 => 'rad',
+ 13230 => 'rad∕s',
+ 13231 => 'rad∕s2',
+ 13232 => 'ps',
+ 13233 => 'ns',
+ 13234 => 'μs',
+ 13235 => 'ms',
+ 13236 => 'pv',
+ 13237 => 'nv',
+ 13238 => 'μv',
+ 13239 => 'mv',
+ 13240 => 'kv',
+ 13241 => 'mv',
+ 13242 => 'pw',
+ 13243 => 'nw',
+ 13244 => 'μw',
+ 13245 => 'mw',
+ 13246 => 'kw',
+ 13247 => 'mw',
+ 13248 => 'kω',
+ 13249 => 'mω',
+ 13251 => 'bq',
+ 13252 => 'cc',
+ 13253 => 'cd',
+ 13254 => 'c∕kg',
+ 13256 => 'db',
+ 13257 => 'gy',
+ 13258 => 'ha',
+ 13259 => 'hp',
+ 13260 => 'in',
+ 13261 => 'kk',
+ 13262 => 'km',
+ 13263 => 'kt',
+ 13264 => 'lm',
+ 13265 => 'ln',
+ 13266 => 'log',
+ 13267 => 'lx',
+ 13268 => 'mb',
+ 13269 => 'mil',
+ 13270 => 'mol',
+ 13271 => 'ph',
+ 13273 => 'ppm',
+ 13274 => 'pr',
+ 13275 => 'sr',
+ 13276 => 'sv',
+ 13277 => 'wb',
+ 13278 => 'v∕m',
+ 13279 => 'a∕m',
+ 13280 => '1日',
+ 13281 => '2日',
+ 13282 => '3日',
+ 13283 => '4日',
+ 13284 => '5日',
+ 13285 => '6日',
+ 13286 => '7日',
+ 13287 => '8日',
+ 13288 => '9日',
+ 13289 => '10日',
+ 13290 => '11日',
+ 13291 => '12日',
+ 13292 => '13日',
+ 13293 => '14日',
+ 13294 => '15日',
+ 13295 => '16日',
+ 13296 => '17日',
+ 13297 => '18日',
+ 13298 => '19日',
+ 13299 => '20日',
+ 13300 => '21日',
+ 13301 => '22日',
+ 13302 => '23日',
+ 13303 => '24日',
+ 13304 => '25日',
+ 13305 => '26日',
+ 13306 => '27日',
+ 13307 => '28日',
+ 13308 => '29日',
+ 13309 => '30日',
+ 13310 => '31日',
+ 13311 => 'gal',
+ 42560 => 'ꙁ',
+ 42562 => 'ꙃ',
+ 42564 => 'ꙅ',
+ 42566 => 'ꙇ',
+ 42568 => 'ꙉ',
+ 42570 => 'ꙋ',
+ 42572 => 'ꙍ',
+ 42574 => 'ꙏ',
+ 42576 => 'ꙑ',
+ 42578 => 'ꙓ',
+ 42580 => 'ꙕ',
+ 42582 => 'ꙗ',
+ 42584 => 'ꙙ',
+ 42586 => 'ꙛ',
+ 42588 => 'ꙝ',
+ 42590 => 'ꙟ',
+ 42592 => 'ꙡ',
+ 42594 => 'ꙣ',
+ 42596 => 'ꙥ',
+ 42598 => 'ꙧ',
+ 42600 => 'ꙩ',
+ 42602 => 'ꙫ',
+ 42604 => 'ꙭ',
+ 42624 => 'ꚁ',
+ 42626 => 'ꚃ',
+ 42628 => 'ꚅ',
+ 42630 => 'ꚇ',
+ 42632 => 'ꚉ',
+ 42634 => 'ꚋ',
+ 42636 => 'ꚍ',
+ 42638 => 'ꚏ',
+ 42640 => 'ꚑ',
+ 42642 => 'ꚓ',
+ 42644 => 'ꚕ',
+ 42646 => 'ꚗ',
+ 42648 => 'ꚙ',
+ 42650 => 'ꚛ',
+ 42652 => 'ъ',
+ 42653 => 'ь',
+ 42786 => 'ꜣ',
+ 42788 => 'ꜥ',
+ 42790 => 'ꜧ',
+ 42792 => 'ꜩ',
+ 42794 => 'ꜫ',
+ 42796 => 'ꜭ',
+ 42798 => 'ꜯ',
+ 42802 => 'ꜳ',
+ 42804 => 'ꜵ',
+ 42806 => 'ꜷ',
+ 42808 => 'ꜹ',
+ 42810 => 'ꜻ',
+ 42812 => 'ꜽ',
+ 42814 => 'ꜿ',
+ 42816 => 'ꝁ',
+ 42818 => 'ꝃ',
+ 42820 => 'ꝅ',
+ 42822 => 'ꝇ',
+ 42824 => 'ꝉ',
+ 42826 => 'ꝋ',
+ 42828 => 'ꝍ',
+ 42830 => 'ꝏ',
+ 42832 => 'ꝑ',
+ 42834 => 'ꝓ',
+ 42836 => 'ꝕ',
+ 42838 => 'ꝗ',
+ 42840 => 'ꝙ',
+ 42842 => 'ꝛ',
+ 42844 => 'ꝝ',
+ 42846 => 'ꝟ',
+ 42848 => 'ꝡ',
+ 42850 => 'ꝣ',
+ 42852 => 'ꝥ',
+ 42854 => 'ꝧ',
+ 42856 => 'ꝩ',
+ 42858 => 'ꝫ',
+ 42860 => 'ꝭ',
+ 42862 => 'ꝯ',
+ 42864 => 'ꝯ',
+ 42873 => 'ꝺ',
+ 42875 => 'ꝼ',
+ 42877 => 'ᵹ',
+ 42878 => 'ꝿ',
+ 42880 => 'ꞁ',
+ 42882 => 'ꞃ',
+ 42884 => 'ꞅ',
+ 42886 => 'ꞇ',
+ 42891 => 'ꞌ',
+ 42893 => 'ɥ',
+ 42896 => 'ꞑ',
+ 42898 => 'ꞓ',
+ 42902 => 'ꞗ',
+ 42904 => 'ꞙ',
+ 42906 => 'ꞛ',
+ 42908 => 'ꞝ',
+ 42910 => 'ꞟ',
+ 42912 => 'ꞡ',
+ 42914 => 'ꞣ',
+ 42916 => 'ꞥ',
+ 42918 => 'ꞧ',
+ 42920 => 'ꞩ',
+ 42922 => 'ɦ',
+ 42923 => 'ɜ',
+ 42924 => 'ɡ',
+ 42925 => 'ɬ',
+ 42926 => 'ɪ',
+ 42928 => 'ʞ',
+ 42929 => 'ʇ',
+ 42930 => 'ʝ',
+ 42931 => 'ꭓ',
+ 42932 => 'ꞵ',
+ 42934 => 'ꞷ',
+ 42936 => 'ꞹ',
+ 42938 => 'ꞻ',
+ 42940 => 'ꞽ',
+ 42942 => 'ꞿ',
+ 42946 => 'ꟃ',
+ 42948 => 'ꞔ',
+ 42949 => 'ʂ',
+ 42950 => 'ᶎ',
+ 42951 => 'ꟈ',
+ 42953 => 'ꟊ',
+ 42997 => 'ꟶ',
+ 43000 => 'ħ',
+ 43001 => 'œ',
+ 43868 => 'ꜧ',
+ 43869 => 'ꬷ',
+ 43870 => 'ɫ',
+ 43871 => 'ꭒ',
+ 43881 => 'ʍ',
+ 43888 => 'Ꭰ',
+ 43889 => 'Ꭱ',
+ 43890 => 'Ꭲ',
+ 43891 => 'Ꭳ',
+ 43892 => 'Ꭴ',
+ 43893 => 'Ꭵ',
+ 43894 => 'Ꭶ',
+ 43895 => 'Ꭷ',
+ 43896 => 'Ꭸ',
+ 43897 => 'Ꭹ',
+ 43898 => 'Ꭺ',
+ 43899 => 'Ꭻ',
+ 43900 => 'Ꭼ',
+ 43901 => 'Ꭽ',
+ 43902 => 'Ꭾ',
+ 43903 => 'Ꭿ',
+ 43904 => 'Ꮀ',
+ 43905 => 'Ꮁ',
+ 43906 => 'Ꮂ',
+ 43907 => 'Ꮃ',
+ 43908 => 'Ꮄ',
+ 43909 => 'Ꮅ',
+ 43910 => 'Ꮆ',
+ 43911 => 'Ꮇ',
+ 43912 => 'Ꮈ',
+ 43913 => 'Ꮉ',
+ 43914 => 'Ꮊ',
+ 43915 => 'Ꮋ',
+ 43916 => 'Ꮌ',
+ 43917 => 'Ꮍ',
+ 43918 => 'Ꮎ',
+ 43919 => 'Ꮏ',
+ 43920 => 'Ꮐ',
+ 43921 => 'Ꮑ',
+ 43922 => 'Ꮒ',
+ 43923 => 'Ꮓ',
+ 43924 => 'Ꮔ',
+ 43925 => 'Ꮕ',
+ 43926 => 'Ꮖ',
+ 43927 => 'Ꮗ',
+ 43928 => 'Ꮘ',
+ 43929 => 'Ꮙ',
+ 43930 => 'Ꮚ',
+ 43931 => 'Ꮛ',
+ 43932 => 'Ꮜ',
+ 43933 => 'Ꮝ',
+ 43934 => 'Ꮞ',
+ 43935 => 'Ꮟ',
+ 43936 => 'Ꮠ',
+ 43937 => 'Ꮡ',
+ 43938 => 'Ꮢ',
+ 43939 => 'Ꮣ',
+ 43940 => 'Ꮤ',
+ 43941 => 'Ꮥ',
+ 43942 => 'Ꮦ',
+ 43943 => 'Ꮧ',
+ 43944 => 'Ꮨ',
+ 43945 => 'Ꮩ',
+ 43946 => 'Ꮪ',
+ 43947 => 'Ꮫ',
+ 43948 => 'Ꮬ',
+ 43949 => 'Ꮭ',
+ 43950 => 'Ꮮ',
+ 43951 => 'Ꮯ',
+ 43952 => 'Ꮰ',
+ 43953 => 'Ꮱ',
+ 43954 => 'Ꮲ',
+ 43955 => 'Ꮳ',
+ 43956 => 'Ꮴ',
+ 43957 => 'Ꮵ',
+ 43958 => 'Ꮶ',
+ 43959 => 'Ꮷ',
+ 43960 => 'Ꮸ',
+ 43961 => 'Ꮹ',
+ 43962 => 'Ꮺ',
+ 43963 => 'Ꮻ',
+ 43964 => 'Ꮼ',
+ 43965 => 'Ꮽ',
+ 43966 => 'Ꮾ',
+ 43967 => 'Ꮿ',
+ 63744 => '豈',
+ 63745 => '更',
+ 63746 => '車',
+ 63747 => '賈',
+ 63748 => '滑',
+ 63749 => '串',
+ 63750 => '句',
+ 63751 => '龜',
+ 63752 => '龜',
+ 63753 => '契',
+ 63754 => '金',
+ 63755 => '喇',
+ 63756 => '奈',
+ 63757 => '懶',
+ 63758 => '癩',
+ 63759 => '羅',
+ 63760 => '蘿',
+ 63761 => '螺',
+ 63762 => '裸',
+ 63763 => '邏',
+ 63764 => '樂',
+ 63765 => '洛',
+ 63766 => '烙',
+ 63767 => '珞',
+ 63768 => '落',
+ 63769 => '酪',
+ 63770 => '駱',
+ 63771 => '亂',
+ 63772 => '卵',
+ 63773 => '欄',
+ 63774 => '爛',
+ 63775 => '蘭',
+ 63776 => '鸞',
+ 63777 => '嵐',
+ 63778 => '濫',
+ 63779 => '藍',
+ 63780 => '襤',
+ 63781 => '拉',
+ 63782 => '臘',
+ 63783 => '蠟',
+ 63784 => '廊',
+ 63785 => '朗',
+ 63786 => '浪',
+ 63787 => '狼',
+ 63788 => '郎',
+ 63789 => '來',
+ 63790 => '冷',
+ 63791 => '勞',
+ 63792 => '擄',
+ 63793 => '櫓',
+ 63794 => '爐',
+ 63795 => '盧',
+ 63796 => '老',
+ 63797 => '蘆',
+ 63798 => '虜',
+ 63799 => '路',
+ 63800 => '露',
+ 63801 => '魯',
+ 63802 => '鷺',
+ 63803 => '碌',
+ 63804 => '祿',
+ 63805 => '綠',
+ 63806 => '菉',
+ 63807 => '錄',
+ 63808 => '鹿',
+ 63809 => '論',
+ 63810 => '壟',
+ 63811 => '弄',
+ 63812 => '籠',
+ 63813 => '聾',
+ 63814 => '牢',
+ 63815 => '磊',
+ 63816 => '賂',
+ 63817 => '雷',
+ 63818 => '壘',
+ 63819 => '屢',
+ 63820 => '樓',
+ 63821 => '淚',
+ 63822 => '漏',
+ 63823 => '累',
+ 63824 => '縷',
+ 63825 => '陋',
+ 63826 => '勒',
+ 63827 => '肋',
+ 63828 => '凜',
+ 63829 => '凌',
+ 63830 => '稜',
+ 63831 => '綾',
+ 63832 => '菱',
+ 63833 => '陵',
+ 63834 => '讀',
+ 63835 => '拏',
+ 63836 => '樂',
+ 63837 => '諾',
+ 63838 => '丹',
+ 63839 => '寧',
+ 63840 => '怒',
+ 63841 => '率',
+ 63842 => '異',
+ 63843 => '北',
+ 63844 => '磻',
+ 63845 => '便',
+ 63846 => '復',
+ 63847 => '不',
+ 63848 => '泌',
+ 63849 => '數',
+ 63850 => '索',
+ 63851 => '參',
+ 63852 => '塞',
+ 63853 => '省',
+ 63854 => '葉',
+ 63855 => '說',
+ 63856 => '殺',
+ 63857 => '辰',
+ 63858 => '沈',
+ 63859 => '拾',
+ 63860 => '若',
+ 63861 => '掠',
+ 63862 => '略',
+ 63863 => '亮',
+ 63864 => '兩',
+ 63865 => '凉',
+ 63866 => '梁',
+ 63867 => '糧',
+ 63868 => '良',
+ 63869 => '諒',
+ 63870 => '量',
+ 63871 => '勵',
+ 63872 => '呂',
+ 63873 => '女',
+ 63874 => '廬',
+ 63875 => '旅',
+ 63876 => '濾',
+ 63877 => '礪',
+ 63878 => '閭',
+ 63879 => '驪',
+ 63880 => '麗',
+ 63881 => '黎',
+ 63882 => '力',
+ 63883 => '曆',
+ 63884 => '歷',
+ 63885 => '轢',
+ 63886 => '年',
+ 63887 => '憐',
+ 63888 => '戀',
+ 63889 => '撚',
+ 63890 => '漣',
+ 63891 => '煉',
+ 63892 => '璉',
+ 63893 => '秊',
+ 63894 => '練',
+ 63895 => '聯',
+ 63896 => '輦',
+ 63897 => '蓮',
+ 63898 => '連',
+ 63899 => '鍊',
+ 63900 => '列',
+ 63901 => '劣',
+ 63902 => '咽',
+ 63903 => '烈',
+ 63904 => '裂',
+ 63905 => '說',
+ 63906 => '廉',
+ 63907 => '念',
+ 63908 => '捻',
+ 63909 => '殮',
+ 63910 => '簾',
+ 63911 => '獵',
+ 63912 => '令',
+ 63913 => '囹',
+ 63914 => '寧',
+ 63915 => '嶺',
+ 63916 => '怜',
+ 63917 => '玲',
+ 63918 => '瑩',
+ 63919 => '羚',
+ 63920 => '聆',
+ 63921 => '鈴',
+ 63922 => '零',
+ 63923 => '靈',
+ 63924 => '領',
+ 63925 => '例',
+ 63926 => '禮',
+ 63927 => '醴',
+ 63928 => '隸',
+ 63929 => '惡',
+ 63930 => '了',
+ 63931 => '僚',
+ 63932 => '寮',
+ 63933 => '尿',
+ 63934 => '料',
+ 63935 => '樂',
+ 63936 => '燎',
+ 63937 => '療',
+ 63938 => '蓼',
+ 63939 => '遼',
+ 63940 => '龍',
+ 63941 => '暈',
+ 63942 => '阮',
+ 63943 => '劉',
+ 63944 => '杻',
+ 63945 => '柳',
+ 63946 => '流',
+ 63947 => '溜',
+ 63948 => '琉',
+ 63949 => '留',
+ 63950 => '硫',
+ 63951 => '紐',
+ 63952 => '類',
+ 63953 => '六',
+ 63954 => '戮',
+ 63955 => '陸',
+ 63956 => '倫',
+ 63957 => '崙',
+ 63958 => '淪',
+ 63959 => '輪',
+ 63960 => '律',
+ 63961 => '慄',
+ 63962 => '栗',
+ 63963 => '率',
+ 63964 => '隆',
+ 63965 => '利',
+ 63966 => '吏',
+ 63967 => '履',
+ 63968 => '易',
+ 63969 => '李',
+ 63970 => '梨',
+ 63971 => '泥',
+ 63972 => '理',
+ 63973 => '痢',
+ 63974 => '罹',
+ 63975 => '裏',
+ 63976 => '裡',
+ 63977 => '里',
+ 63978 => '離',
+ 63979 => '匿',
+ 63980 => '溺',
+ 63981 => '吝',
+ 63982 => '燐',
+ 63983 => '璘',
+ 63984 => '藺',
+ 63985 => '隣',
+ 63986 => '鱗',
+ 63987 => '麟',
+ 63988 => '林',
+ 63989 => '淋',
+ 63990 => '臨',
+ 63991 => '立',
+ 63992 => '笠',
+ 63993 => '粒',
+ 63994 => '狀',
+ 63995 => '炙',
+ 63996 => '識',
+ 63997 => '什',
+ 63998 => '茶',
+ 63999 => '刺',
+ 64000 => '切',
+ 64001 => '度',
+ 64002 => '拓',
+ 64003 => '糖',
+ 64004 => '宅',
+ 64005 => '洞',
+ 64006 => '暴',
+ 64007 => '輻',
+ 64008 => '行',
+ 64009 => '降',
+ 64010 => '見',
+ 64011 => '廓',
+ 64012 => '兀',
+ 64013 => '嗀',
+ 64016 => '塚',
+ 64018 => '晴',
+ 64021 => '凞',
+ 64022 => '猪',
+ 64023 => '益',
+ 64024 => '礼',
+ 64025 => '神',
+ 64026 => '祥',
+ 64027 => '福',
+ 64028 => '靖',
+ 64029 => '精',
+ 64030 => '羽',
+ 64032 => '蘒',
+ 64034 => '諸',
+ 64037 => '逸',
+ 64038 => '都',
+ 64042 => '飯',
+ 64043 => '飼',
+ 64044 => '館',
+ 64045 => '鶴',
+ 64046 => '郞',
+ 64047 => '隷',
+ 64048 => '侮',
+ 64049 => '僧',
+ 64050 => '免',
+ 64051 => '勉',
+ 64052 => '勤',
+ 64053 => '卑',
+ 64054 => '喝',
+ 64055 => '嘆',
+ 64056 => '器',
+ 64057 => '塀',
+ 64058 => '墨',
+ 64059 => '層',
+ 64060 => '屮',
+ 64061 => '悔',
+ 64062 => '慨',
+ 64063 => '憎',
+ 64064 => '懲',
+ 64065 => '敏',
+ 64066 => '既',
+ 64067 => '暑',
+ 64068 => '梅',
+ 64069 => '海',
+ 64070 => '渚',
+ 64071 => '漢',
+ 64072 => '煮',
+ 64073 => '爫',
+ 64074 => '琢',
+ 64075 => '碑',
+ 64076 => '社',
+ 64077 => '祉',
+ 64078 => '祈',
+ 64079 => '祐',
+ 64080 => '祖',
+ 64081 => '祝',
+ 64082 => '禍',
+ 64083 => '禎',
+ 64084 => '穀',
+ 64085 => '突',
+ 64086 => '節',
+ 64087 => '練',
+ 64088 => '縉',
+ 64089 => '繁',
+ 64090 => '署',
+ 64091 => '者',
+ 64092 => '臭',
+ 64093 => '艹',
+ 64094 => '艹',
+ 64095 => '著',
+ 64096 => '褐',
+ 64097 => '視',
+ 64098 => '謁',
+ 64099 => '謹',
+ 64100 => '賓',
+ 64101 => '贈',
+ 64102 => '辶',
+ 64103 => '逸',
+ 64104 => '難',
+ 64105 => '響',
+ 64106 => '頻',
+ 64107 => '恵',
+ 64108 => '𤋮',
+ 64109 => '舘',
+ 64112 => '並',
+ 64113 => '况',
+ 64114 => '全',
+ 64115 => '侀',
+ 64116 => '充',
+ 64117 => '冀',
+ 64118 => '勇',
+ 64119 => '勺',
+ 64120 => '喝',
+ 64121 => '啕',
+ 64122 => '喙',
+ 64123 => '嗢',
+ 64124 => '塚',
+ 64125 => '墳',
+ 64126 => '奄',
+ 64127 => '奔',
+ 64128 => '婢',
+ 64129 => '嬨',
+ 64130 => '廒',
+ 64131 => '廙',
+ 64132 => '彩',
+ 64133 => '徭',
+ 64134 => '惘',
+ 64135 => '慎',
+ 64136 => '愈',
+ 64137 => '憎',
+ 64138 => '慠',
+ 64139 => '懲',
+ 64140 => '戴',
+ 64141 => '揄',
+ 64142 => '搜',
+ 64143 => '摒',
+ 64144 => '敖',
+ 64145 => '晴',
+ 64146 => '朗',
+ 64147 => '望',
+ 64148 => '杖',
+ 64149 => '歹',
+ 64150 => '殺',
+ 64151 => '流',
+ 64152 => '滛',
+ 64153 => '滋',
+ 64154 => '漢',
+ 64155 => '瀞',
+ 64156 => '煮',
+ 64157 => '瞧',
+ 64158 => '爵',
+ 64159 => '犯',
+ 64160 => '猪',
+ 64161 => '瑱',
+ 64162 => '甆',
+ 64163 => '画',
+ 64164 => '瘝',
+ 64165 => '瘟',
+ 64166 => '益',
+ 64167 => '盛',
+ 64168 => '直',
+ 64169 => '睊',
+ 64170 => '着',
+ 64171 => '磌',
+ 64172 => '窱',
+ 64173 => '節',
+ 64174 => '类',
+ 64175 => '絛',
+ 64176 => '練',
+ 64177 => '缾',
+ 64178 => '者',
+ 64179 => '荒',
+ 64180 => '華',
+ 64181 => '蝹',
+ 64182 => '襁',
+ 64183 => '覆',
+ 64184 => '視',
+ 64185 => '調',
+ 64186 => '諸',
+ 64187 => '請',
+ 64188 => '謁',
+ 64189 => '諾',
+ 64190 => '諭',
+ 64191 => '謹',
+ 64192 => '變',
+ 64193 => '贈',
+ 64194 => '輸',
+ 64195 => '遲',
+ 64196 => '醙',
+ 64197 => '鉶',
+ 64198 => '陼',
+ 64199 => '難',
+ 64200 => '靖',
+ 64201 => '韛',
+ 64202 => '響',
+ 64203 => '頋',
+ 64204 => '頻',
+ 64205 => '鬒',
+ 64206 => '龜',
+ 64207 => '𢡊',
+ 64208 => '𢡄',
+ 64209 => '𣏕',
+ 64210 => '㮝',
+ 64211 => '䀘',
+ 64212 => '䀹',
+ 64213 => '𥉉',
+ 64214 => '𥳐',
+ 64215 => '𧻓',
+ 64216 => '齃',
+ 64217 => '龎',
+ 64256 => 'ff',
+ 64257 => 'fi',
+ 64258 => 'fl',
+ 64259 => 'ffi',
+ 64260 => 'ffl',
+ 64261 => 'st',
+ 64262 => 'st',
+ 64275 => 'մն',
+ 64276 => 'մե',
+ 64277 => 'մի',
+ 64278 => 'վն',
+ 64279 => 'մխ',
+ 64285 => 'יִ',
+ 64287 => 'ײַ',
+ 64288 => 'ע',
+ 64289 => 'א',
+ 64290 => 'ד',
+ 64291 => 'ה',
+ 64292 => 'כ',
+ 64293 => 'ל',
+ 64294 => 'ם',
+ 64295 => 'ר',
+ 64296 => 'ת',
+ 64298 => 'שׁ',
+ 64299 => 'שׂ',
+ 64300 => 'שּׁ',
+ 64301 => 'שּׂ',
+ 64302 => 'אַ',
+ 64303 => 'אָ',
+ 64304 => 'אּ',
+ 64305 => 'בּ',
+ 64306 => 'גּ',
+ 64307 => 'דּ',
+ 64308 => 'הּ',
+ 64309 => 'וּ',
+ 64310 => 'זּ',
+ 64312 => 'טּ',
+ 64313 => 'יּ',
+ 64314 => 'ךּ',
+ 64315 => 'כּ',
+ 64316 => 'לּ',
+ 64318 => 'מּ',
+ 64320 => 'נּ',
+ 64321 => 'סּ',
+ 64323 => 'ףּ',
+ 64324 => 'פּ',
+ 64326 => 'צּ',
+ 64327 => 'קּ',
+ 64328 => 'רּ',
+ 64329 => 'שּ',
+ 64330 => 'תּ',
+ 64331 => 'וֹ',
+ 64332 => 'בֿ',
+ 64333 => 'כֿ',
+ 64334 => 'פֿ',
+ 64335 => 'אל',
+ 64336 => 'ٱ',
+ 64337 => 'ٱ',
+ 64338 => 'ٻ',
+ 64339 => 'ٻ',
+ 64340 => 'ٻ',
+ 64341 => 'ٻ',
+ 64342 => 'پ',
+ 64343 => 'پ',
+ 64344 => 'پ',
+ 64345 => 'پ',
+ 64346 => 'ڀ',
+ 64347 => 'ڀ',
+ 64348 => 'ڀ',
+ 64349 => 'ڀ',
+ 64350 => 'ٺ',
+ 64351 => 'ٺ',
+ 64352 => 'ٺ',
+ 64353 => 'ٺ',
+ 64354 => 'ٿ',
+ 64355 => 'ٿ',
+ 64356 => 'ٿ',
+ 64357 => 'ٿ',
+ 64358 => 'ٹ',
+ 64359 => 'ٹ',
+ 64360 => 'ٹ',
+ 64361 => 'ٹ',
+ 64362 => 'ڤ',
+ 64363 => 'ڤ',
+ 64364 => 'ڤ',
+ 64365 => 'ڤ',
+ 64366 => 'ڦ',
+ 64367 => 'ڦ',
+ 64368 => 'ڦ',
+ 64369 => 'ڦ',
+ 64370 => 'ڄ',
+ 64371 => 'ڄ',
+ 64372 => 'ڄ',
+ 64373 => 'ڄ',
+ 64374 => 'ڃ',
+ 64375 => 'ڃ',
+ 64376 => 'ڃ',
+ 64377 => 'ڃ',
+ 64378 => 'چ',
+ 64379 => 'چ',
+ 64380 => 'چ',
+ 64381 => 'چ',
+ 64382 => 'ڇ',
+ 64383 => 'ڇ',
+ 64384 => 'ڇ',
+ 64385 => 'ڇ',
+ 64386 => 'ڍ',
+ 64387 => 'ڍ',
+ 64388 => 'ڌ',
+ 64389 => 'ڌ',
+ 64390 => 'ڎ',
+ 64391 => 'ڎ',
+ 64392 => 'ڈ',
+ 64393 => 'ڈ',
+ 64394 => 'ژ',
+ 64395 => 'ژ',
+ 64396 => 'ڑ',
+ 64397 => 'ڑ',
+ 64398 => 'ک',
+ 64399 => 'ک',
+ 64400 => 'ک',
+ 64401 => 'ک',
+ 64402 => 'گ',
+ 64403 => 'گ',
+ 64404 => 'گ',
+ 64405 => 'گ',
+ 64406 => 'ڳ',
+ 64407 => 'ڳ',
+ 64408 => 'ڳ',
+ 64409 => 'ڳ',
+ 64410 => 'ڱ',
+ 64411 => 'ڱ',
+ 64412 => 'ڱ',
+ 64413 => 'ڱ',
+ 64414 => 'ں',
+ 64415 => 'ں',
+ 64416 => 'ڻ',
+ 64417 => 'ڻ',
+ 64418 => 'ڻ',
+ 64419 => 'ڻ',
+ 64420 => 'ۀ',
+ 64421 => 'ۀ',
+ 64422 => 'ہ',
+ 64423 => 'ہ',
+ 64424 => 'ہ',
+ 64425 => 'ہ',
+ 64426 => 'ھ',
+ 64427 => 'ھ',
+ 64428 => 'ھ',
+ 64429 => 'ھ',
+ 64430 => 'ے',
+ 64431 => 'ے',
+ 64432 => 'ۓ',
+ 64433 => 'ۓ',
+ 64467 => 'ڭ',
+ 64468 => 'ڭ',
+ 64469 => 'ڭ',
+ 64470 => 'ڭ',
+ 64471 => 'ۇ',
+ 64472 => 'ۇ',
+ 64473 => 'ۆ',
+ 64474 => 'ۆ',
+ 64475 => 'ۈ',
+ 64476 => 'ۈ',
+ 64477 => 'ۇٴ',
+ 64478 => 'ۋ',
+ 64479 => 'ۋ',
+ 64480 => 'ۅ',
+ 64481 => 'ۅ',
+ 64482 => 'ۉ',
+ 64483 => 'ۉ',
+ 64484 => 'ې',
+ 64485 => 'ې',
+ 64486 => 'ې',
+ 64487 => 'ې',
+ 64488 => 'ى',
+ 64489 => 'ى',
+ 64490 => 'ئا',
+ 64491 => 'ئا',
+ 64492 => 'ئە',
+ 64493 => 'ئە',
+ 64494 => 'ئو',
+ 64495 => 'ئو',
+ 64496 => 'ئۇ',
+ 64497 => 'ئۇ',
+ 64498 => 'ئۆ',
+ 64499 => 'ئۆ',
+ 64500 => 'ئۈ',
+ 64501 => 'ئۈ',
+ 64502 => 'ئې',
+ 64503 => 'ئې',
+ 64504 => 'ئې',
+ 64505 => 'ئى',
+ 64506 => 'ئى',
+ 64507 => 'ئى',
+ 64508 => 'ی',
+ 64509 => 'ی',
+ 64510 => 'ی',
+ 64511 => 'ی',
+ 64512 => 'ئج',
+ 64513 => 'ئح',
+ 64514 => 'ئم',
+ 64515 => 'ئى',
+ 64516 => 'ئي',
+ 64517 => 'بج',
+ 64518 => 'بح',
+ 64519 => 'بخ',
+ 64520 => 'بم',
+ 64521 => 'بى',
+ 64522 => 'بي',
+ 64523 => 'تج',
+ 64524 => 'تح',
+ 64525 => 'تخ',
+ 64526 => 'تم',
+ 64527 => 'تى',
+ 64528 => 'تي',
+ 64529 => 'ثج',
+ 64530 => 'ثم',
+ 64531 => 'ثى',
+ 64532 => 'ثي',
+ 64533 => 'جح',
+ 64534 => 'جم',
+ 64535 => 'حج',
+ 64536 => 'حم',
+ 64537 => 'خج',
+ 64538 => 'خح',
+ 64539 => 'خم',
+ 64540 => 'سج',
+ 64541 => 'سح',
+ 64542 => 'سخ',
+ 64543 => 'سم',
+ 64544 => 'صح',
+ 64545 => 'صم',
+ 64546 => 'ضج',
+ 64547 => 'ضح',
+ 64548 => 'ضخ',
+ 64549 => 'ضم',
+ 64550 => 'طح',
+ 64551 => 'طم',
+ 64552 => 'ظم',
+ 64553 => 'عج',
+ 64554 => 'عم',
+ 64555 => 'غج',
+ 64556 => 'غم',
+ 64557 => 'فج',
+ 64558 => 'فح',
+ 64559 => 'فخ',
+ 64560 => 'فم',
+ 64561 => 'فى',
+ 64562 => 'في',
+ 64563 => 'قح',
+ 64564 => 'قم',
+ 64565 => 'قى',
+ 64566 => 'قي',
+ 64567 => 'كا',
+ 64568 => 'كج',
+ 64569 => 'كح',
+ 64570 => 'كخ',
+ 64571 => 'كل',
+ 64572 => 'كم',
+ 64573 => 'كى',
+ 64574 => 'كي',
+ 64575 => 'لج',
+ 64576 => 'لح',
+ 64577 => 'لخ',
+ 64578 => 'لم',
+ 64579 => 'لى',
+ 64580 => 'لي',
+ 64581 => 'مج',
+ 64582 => 'مح',
+ 64583 => 'مخ',
+ 64584 => 'مم',
+ 64585 => 'مى',
+ 64586 => 'مي',
+ 64587 => 'نج',
+ 64588 => 'نح',
+ 64589 => 'نخ',
+ 64590 => 'نم',
+ 64591 => 'نى',
+ 64592 => 'ني',
+ 64593 => 'هج',
+ 64594 => 'هم',
+ 64595 => 'هى',
+ 64596 => 'هي',
+ 64597 => 'يج',
+ 64598 => 'يح',
+ 64599 => 'يخ',
+ 64600 => 'يم',
+ 64601 => 'يى',
+ 64602 => 'يي',
+ 64603 => 'ذٰ',
+ 64604 => 'رٰ',
+ 64605 => 'ىٰ',
+ 64612 => 'ئر',
+ 64613 => 'ئز',
+ 64614 => 'ئم',
+ 64615 => 'ئن',
+ 64616 => 'ئى',
+ 64617 => 'ئي',
+ 64618 => 'بر',
+ 64619 => 'بز',
+ 64620 => 'بم',
+ 64621 => 'بن',
+ 64622 => 'بى',
+ 64623 => 'بي',
+ 64624 => 'تر',
+ 64625 => 'تز',
+ 64626 => 'تم',
+ 64627 => 'تن',
+ 64628 => 'تى',
+ 64629 => 'تي',
+ 64630 => 'ثر',
+ 64631 => 'ثز',
+ 64632 => 'ثم',
+ 64633 => 'ثن',
+ 64634 => 'ثى',
+ 64635 => 'ثي',
+ 64636 => 'فى',
+ 64637 => 'في',
+ 64638 => 'قى',
+ 64639 => 'قي',
+ 64640 => 'كا',
+ 64641 => 'كل',
+ 64642 => 'كم',
+ 64643 => 'كى',
+ 64644 => 'كي',
+ 64645 => 'لم',
+ 64646 => 'لى',
+ 64647 => 'لي',
+ 64648 => 'ما',
+ 64649 => 'مم',
+ 64650 => 'نر',
+ 64651 => 'نز',
+ 64652 => 'نم',
+ 64653 => 'نن',
+ 64654 => 'نى',
+ 64655 => 'ني',
+ 64656 => 'ىٰ',
+ 64657 => 'ير',
+ 64658 => 'يز',
+ 64659 => 'يم',
+ 64660 => 'ين',
+ 64661 => 'يى',
+ 64662 => 'يي',
+ 64663 => 'ئج',
+ 64664 => 'ئح',
+ 64665 => 'ئخ',
+ 64666 => 'ئم',
+ 64667 => 'ئه',
+ 64668 => 'بج',
+ 64669 => 'بح',
+ 64670 => 'بخ',
+ 64671 => 'بم',
+ 64672 => 'به',
+ 64673 => 'تج',
+ 64674 => 'تح',
+ 64675 => 'تخ',
+ 64676 => 'تم',
+ 64677 => 'ته',
+ 64678 => 'ثم',
+ 64679 => 'جح',
+ 64680 => 'جم',
+ 64681 => 'حج',
+ 64682 => 'حم',
+ 64683 => 'خج',
+ 64684 => 'خم',
+ 64685 => 'سج',
+ 64686 => 'سح',
+ 64687 => 'سخ',
+ 64688 => 'سم',
+ 64689 => 'صح',
+ 64690 => 'صخ',
+ 64691 => 'صم',
+ 64692 => 'ضج',
+ 64693 => 'ضح',
+ 64694 => 'ضخ',
+ 64695 => 'ضم',
+ 64696 => 'طح',
+ 64697 => 'ظم',
+ 64698 => 'عج',
+ 64699 => 'عم',
+ 64700 => 'غج',
+ 64701 => 'غم',
+ 64702 => 'فج',
+ 64703 => 'فح',
+ 64704 => 'فخ',
+ 64705 => 'فم',
+ 64706 => 'قح',
+ 64707 => 'قم',
+ 64708 => 'كج',
+ 64709 => 'كح',
+ 64710 => 'كخ',
+ 64711 => 'كل',
+ 64712 => 'كم',
+ 64713 => 'لج',
+ 64714 => 'لح',
+ 64715 => 'لخ',
+ 64716 => 'لم',
+ 64717 => 'له',
+ 64718 => 'مج',
+ 64719 => 'مح',
+ 64720 => 'مخ',
+ 64721 => 'مم',
+ 64722 => 'نج',
+ 64723 => 'نح',
+ 64724 => 'نخ',
+ 64725 => 'نم',
+ 64726 => 'نه',
+ 64727 => 'هج',
+ 64728 => 'هم',
+ 64729 => 'هٰ',
+ 64730 => 'يج',
+ 64731 => 'يح',
+ 64732 => 'يخ',
+ 64733 => 'يم',
+ 64734 => 'يه',
+ 64735 => 'ئم',
+ 64736 => 'ئه',
+ 64737 => 'بم',
+ 64738 => 'به',
+ 64739 => 'تم',
+ 64740 => 'ته',
+ 64741 => 'ثم',
+ 64742 => 'ثه',
+ 64743 => 'سم',
+ 64744 => 'سه',
+ 64745 => 'شم',
+ 64746 => 'شه',
+ 64747 => 'كل',
+ 64748 => 'كم',
+ 64749 => 'لم',
+ 64750 => 'نم',
+ 64751 => 'نه',
+ 64752 => 'يم',
+ 64753 => 'يه',
+ 64754 => 'ـَّ',
+ 64755 => 'ـُّ',
+ 64756 => 'ـِّ',
+ 64757 => 'طى',
+ 64758 => 'طي',
+ 64759 => 'عى',
+ 64760 => 'عي',
+ 64761 => 'غى',
+ 64762 => 'غي',
+ 64763 => 'سى',
+ 64764 => 'سي',
+ 64765 => 'شى',
+ 64766 => 'شي',
+ 64767 => 'حى',
+ 64768 => 'حي',
+ 64769 => 'جى',
+ 64770 => 'جي',
+ 64771 => 'خى',
+ 64772 => 'خي',
+ 64773 => 'صى',
+ 64774 => 'صي',
+ 64775 => 'ضى',
+ 64776 => 'ضي',
+ 64777 => 'شج',
+ 64778 => 'شح',
+ 64779 => 'شخ',
+ 64780 => 'شم',
+ 64781 => 'شر',
+ 64782 => 'سر',
+ 64783 => 'صر',
+ 64784 => 'ضر',
+ 64785 => 'طى',
+ 64786 => 'طي',
+ 64787 => 'عى',
+ 64788 => 'عي',
+ 64789 => 'غى',
+ 64790 => 'غي',
+ 64791 => 'سى',
+ 64792 => 'سي',
+ 64793 => 'شى',
+ 64794 => 'شي',
+ 64795 => 'حى',
+ 64796 => 'حي',
+ 64797 => 'جى',
+ 64798 => 'جي',
+ 64799 => 'خى',
+ 64800 => 'خي',
+ 64801 => 'صى',
+ 64802 => 'صي',
+ 64803 => 'ضى',
+ 64804 => 'ضي',
+ 64805 => 'شج',
+ 64806 => 'شح',
+ 64807 => 'شخ',
+ 64808 => 'شم',
+ 64809 => 'شر',
+ 64810 => 'سر',
+ 64811 => 'صر',
+ 64812 => 'ضر',
+ 64813 => 'شج',
+ 64814 => 'شح',
+ 64815 => 'شخ',
+ 64816 => 'شم',
+ 64817 => 'سه',
+ 64818 => 'شه',
+ 64819 => 'طم',
+ 64820 => 'سج',
+ 64821 => 'سح',
+ 64822 => 'سخ',
+ 64823 => 'شج',
+ 64824 => 'شح',
+ 64825 => 'شخ',
+ 64826 => 'طم',
+ 64827 => 'ظم',
+ 64828 => 'اً',
+ 64829 => 'اً',
+ 64848 => 'تجم',
+ 64849 => 'تحج',
+ 64850 => 'تحج',
+ 64851 => 'تحم',
+ 64852 => 'تخم',
+ 64853 => 'تمج',
+ 64854 => 'تمح',
+ 64855 => 'تمخ',
+ 64856 => 'جمح',
+ 64857 => 'جمح',
+ 64858 => 'حمي',
+ 64859 => 'حمى',
+ 64860 => 'سحج',
+ 64861 => 'سجح',
+ 64862 => 'سجى',
+ 64863 => 'سمح',
+ 64864 => 'سمح',
+ 64865 => 'سمج',
+ 64866 => 'سمم',
+ 64867 => 'سمم',
+ 64868 => 'صحح',
+ 64869 => 'صحح',
+ 64870 => 'صمم',
+ 64871 => 'شحم',
+ 64872 => 'شحم',
+ 64873 => 'شجي',
+ 64874 => 'شمخ',
+ 64875 => 'شمخ',
+ 64876 => 'شمم',
+ 64877 => 'شمم',
+ 64878 => 'ضحى',
+ 64879 => 'ضخم',
+ 64880 => 'ضخم',
+ 64881 => 'طمح',
+ 64882 => 'طمح',
+ 64883 => 'طمم',
+ 64884 => 'طمي',
+ 64885 => 'عجم',
+ 64886 => 'عمم',
+ 64887 => 'عمم',
+ 64888 => 'عمى',
+ 64889 => 'غمم',
+ 64890 => 'غمي',
+ 64891 => 'غمى',
+ 64892 => 'فخم',
+ 64893 => 'فخم',
+ 64894 => 'قمح',
+ 64895 => 'قمم',
+ 64896 => 'لحم',
+ 64897 => 'لحي',
+ 64898 => 'لحى',
+ 64899 => 'لجج',
+ 64900 => 'لجج',
+ 64901 => 'لخم',
+ 64902 => 'لخم',
+ 64903 => 'لمح',
+ 64904 => 'لمح',
+ 64905 => 'محج',
+ 64906 => 'محم',
+ 64907 => 'محي',
+ 64908 => 'مجح',
+ 64909 => 'مجم',
+ 64910 => 'مخج',
+ 64911 => 'مخم',
+ 64914 => 'مجخ',
+ 64915 => 'همج',
+ 64916 => 'همم',
+ 64917 => 'نحم',
+ 64918 => 'نحى',
+ 64919 => 'نجم',
+ 64920 => 'نجم',
+ 64921 => 'نجى',
+ 64922 => 'نمي',
+ 64923 => 'نمى',
+ 64924 => 'يمم',
+ 64925 => 'يمم',
+ 64926 => 'بخي',
+ 64927 => 'تجي',
+ 64928 => 'تجى',
+ 64929 => 'تخي',
+ 64930 => 'تخى',
+ 64931 => 'تمي',
+ 64932 => 'تمى',
+ 64933 => 'جمي',
+ 64934 => 'جحى',
+ 64935 => 'جمى',
+ 64936 => 'سخى',
+ 64937 => 'صحي',
+ 64938 => 'شحي',
+ 64939 => 'ضحي',
+ 64940 => 'لجي',
+ 64941 => 'لمي',
+ 64942 => 'يحي',
+ 64943 => 'يجي',
+ 64944 => 'يمي',
+ 64945 => 'ممي',
+ 64946 => 'قمي',
+ 64947 => 'نحي',
+ 64948 => 'قمح',
+ 64949 => 'لحم',
+ 64950 => 'عمي',
+ 64951 => 'كمي',
+ 64952 => 'نجح',
+ 64953 => 'مخي',
+ 64954 => 'لجم',
+ 64955 => 'كمم',
+ 64956 => 'لجم',
+ 64957 => 'نجح',
+ 64958 => 'جحي',
+ 64959 => 'حجي',
+ 64960 => 'مجي',
+ 64961 => 'فمي',
+ 64962 => 'بحي',
+ 64963 => 'كمم',
+ 64964 => 'عجم',
+ 64965 => 'صمم',
+ 64966 => 'سخي',
+ 64967 => 'نجي',
+ 65008 => 'صلے',
+ 65009 => 'قلے',
+ 65010 => 'الله',
+ 65011 => 'اكبر',
+ 65012 => 'محمد',
+ 65013 => 'صلعم',
+ 65014 => 'رسول',
+ 65015 => 'عليه',
+ 65016 => 'وسلم',
+ 65017 => 'صلى',
+ 65020 => 'ریال',
+ 65041 => '、',
+ 65047 => '〖',
+ 65048 => '〗',
+ 65073 => '—',
+ 65074 => '–',
+ 65081 => '〔',
+ 65082 => '〕',
+ 65083 => '【',
+ 65084 => '】',
+ 65085 => '《',
+ 65086 => '》',
+ 65087 => '〈',
+ 65088 => '〉',
+ 65089 => '「',
+ 65090 => '」',
+ 65091 => '『',
+ 65092 => '』',
+ 65105 => '、',
+ 65112 => '—',
+ 65117 => '〔',
+ 65118 => '〕',
+ 65123 => '-',
+ 65137 => 'ـً',
+ 65143 => 'ـَ',
+ 65145 => 'ـُ',
+ 65147 => 'ـِ',
+ 65149 => 'ـّ',
+ 65151 => 'ـْ',
+ 65152 => 'ء',
+ 65153 => 'آ',
+ 65154 => 'آ',
+ 65155 => 'أ',
+ 65156 => 'أ',
+ 65157 => 'ؤ',
+ 65158 => 'ؤ',
+ 65159 => 'إ',
+ 65160 => 'إ',
+ 65161 => 'ئ',
+ 65162 => 'ئ',
+ 65163 => 'ئ',
+ 65164 => 'ئ',
+ 65165 => 'ا',
+ 65166 => 'ا',
+ 65167 => 'ب',
+ 65168 => 'ب',
+ 65169 => 'ب',
+ 65170 => 'ب',
+ 65171 => 'ة',
+ 65172 => 'ة',
+ 65173 => 'ت',
+ 65174 => 'ت',
+ 65175 => 'ت',
+ 65176 => 'ت',
+ 65177 => 'ث',
+ 65178 => 'ث',
+ 65179 => 'ث',
+ 65180 => 'ث',
+ 65181 => 'ج',
+ 65182 => 'ج',
+ 65183 => 'ج',
+ 65184 => 'ج',
+ 65185 => 'ح',
+ 65186 => 'ح',
+ 65187 => 'ح',
+ 65188 => 'ح',
+ 65189 => 'خ',
+ 65190 => 'خ',
+ 65191 => 'خ',
+ 65192 => 'خ',
+ 65193 => 'د',
+ 65194 => 'د',
+ 65195 => 'ذ',
+ 65196 => 'ذ',
+ 65197 => 'ر',
+ 65198 => 'ر',
+ 65199 => 'ز',
+ 65200 => 'ز',
+ 65201 => 'س',
+ 65202 => 'س',
+ 65203 => 'س',
+ 65204 => 'س',
+ 65205 => 'ش',
+ 65206 => 'ش',
+ 65207 => 'ش',
+ 65208 => 'ش',
+ 65209 => 'ص',
+ 65210 => 'ص',
+ 65211 => 'ص',
+ 65212 => 'ص',
+ 65213 => 'ض',
+ 65214 => 'ض',
+ 65215 => 'ض',
+ 65216 => 'ض',
+ 65217 => 'ط',
+ 65218 => 'ط',
+ 65219 => 'ط',
+ 65220 => 'ط',
+ 65221 => 'ظ',
+ 65222 => 'ظ',
+ 65223 => 'ظ',
+ 65224 => 'ظ',
+ 65225 => 'ع',
+ 65226 => 'ع',
+ 65227 => 'ع',
+ 65228 => 'ع',
+ 65229 => 'غ',
+ 65230 => 'غ',
+ 65231 => 'غ',
+ 65232 => 'غ',
+ 65233 => 'ف',
+ 65234 => 'ف',
+ 65235 => 'ف',
+ 65236 => 'ف',
+ 65237 => 'ق',
+ 65238 => 'ق',
+ 65239 => 'ق',
+ 65240 => 'ق',
+ 65241 => 'ك',
+ 65242 => 'ك',
+ 65243 => 'ك',
+ 65244 => 'ك',
+ 65245 => 'ل',
+ 65246 => 'ل',
+ 65247 => 'ل',
+ 65248 => 'ل',
+ 65249 => 'م',
+ 65250 => 'م',
+ 65251 => 'م',
+ 65252 => 'م',
+ 65253 => 'ن',
+ 65254 => 'ن',
+ 65255 => 'ن',
+ 65256 => 'ن',
+ 65257 => 'ه',
+ 65258 => 'ه',
+ 65259 => 'ه',
+ 65260 => 'ه',
+ 65261 => 'و',
+ 65262 => 'و',
+ 65263 => 'ى',
+ 65264 => 'ى',
+ 65265 => 'ي',
+ 65266 => 'ي',
+ 65267 => 'ي',
+ 65268 => 'ي',
+ 65269 => 'لآ',
+ 65270 => 'لآ',
+ 65271 => 'لأ',
+ 65272 => 'لأ',
+ 65273 => 'لإ',
+ 65274 => 'لإ',
+ 65275 => 'لا',
+ 65276 => 'لا',
+ 65293 => '-',
+ 65294 => '.',
+ 65296 => '0',
+ 65297 => '1',
+ 65298 => '2',
+ 65299 => '3',
+ 65300 => '4',
+ 65301 => '5',
+ 65302 => '6',
+ 65303 => '7',
+ 65304 => '8',
+ 65305 => '9',
+ 65313 => 'a',
+ 65314 => 'b',
+ 65315 => 'c',
+ 65316 => 'd',
+ 65317 => 'e',
+ 65318 => 'f',
+ 65319 => 'g',
+ 65320 => 'h',
+ 65321 => 'i',
+ 65322 => 'j',
+ 65323 => 'k',
+ 65324 => 'l',
+ 65325 => 'm',
+ 65326 => 'n',
+ 65327 => 'o',
+ 65328 => 'p',
+ 65329 => 'q',
+ 65330 => 'r',
+ 65331 => 's',
+ 65332 => 't',
+ 65333 => 'u',
+ 65334 => 'v',
+ 65335 => 'w',
+ 65336 => 'x',
+ 65337 => 'y',
+ 65338 => 'z',
+ 65345 => 'a',
+ 65346 => 'b',
+ 65347 => 'c',
+ 65348 => 'd',
+ 65349 => 'e',
+ 65350 => 'f',
+ 65351 => 'g',
+ 65352 => 'h',
+ 65353 => 'i',
+ 65354 => 'j',
+ 65355 => 'k',
+ 65356 => 'l',
+ 65357 => 'm',
+ 65358 => 'n',
+ 65359 => 'o',
+ 65360 => 'p',
+ 65361 => 'q',
+ 65362 => 'r',
+ 65363 => 's',
+ 65364 => 't',
+ 65365 => 'u',
+ 65366 => 'v',
+ 65367 => 'w',
+ 65368 => 'x',
+ 65369 => 'y',
+ 65370 => 'z',
+ 65375 => '⦅',
+ 65376 => '⦆',
+ 65377 => '.',
+ 65378 => '「',
+ 65379 => '」',
+ 65380 => '、',
+ 65381 => '・',
+ 65382 => 'ヲ',
+ 65383 => 'ァ',
+ 65384 => 'ィ',
+ 65385 => 'ゥ',
+ 65386 => 'ェ',
+ 65387 => 'ォ',
+ 65388 => 'ャ',
+ 65389 => 'ュ',
+ 65390 => 'ョ',
+ 65391 => 'ッ',
+ 65392 => 'ー',
+ 65393 => 'ア',
+ 65394 => 'イ',
+ 65395 => 'ウ',
+ 65396 => 'エ',
+ 65397 => 'オ',
+ 65398 => 'カ',
+ 65399 => 'キ',
+ 65400 => 'ク',
+ 65401 => 'ケ',
+ 65402 => 'コ',
+ 65403 => 'サ',
+ 65404 => 'シ',
+ 65405 => 'ス',
+ 65406 => 'セ',
+ 65407 => 'ソ',
+ 65408 => 'タ',
+ 65409 => 'チ',
+ 65410 => 'ツ',
+ 65411 => 'テ',
+ 65412 => 'ト',
+ 65413 => 'ナ',
+ 65414 => 'ニ',
+ 65415 => 'ヌ',
+ 65416 => 'ネ',
+ 65417 => 'ノ',
+ 65418 => 'ハ',
+ 65419 => 'ヒ',
+ 65420 => 'フ',
+ 65421 => 'ヘ',
+ 65422 => 'ホ',
+ 65423 => 'マ',
+ 65424 => 'ミ',
+ 65425 => 'ム',
+ 65426 => 'メ',
+ 65427 => 'モ',
+ 65428 => 'ヤ',
+ 65429 => 'ユ',
+ 65430 => 'ヨ',
+ 65431 => 'ラ',
+ 65432 => 'リ',
+ 65433 => 'ル',
+ 65434 => 'レ',
+ 65435 => 'ロ',
+ 65436 => 'ワ',
+ 65437 => 'ン',
+ 65438 => '゙',
+ 65439 => '゚',
+ 65441 => 'ᄀ',
+ 65442 => 'ᄁ',
+ 65443 => 'ᆪ',
+ 65444 => 'ᄂ',
+ 65445 => 'ᆬ',
+ 65446 => 'ᆭ',
+ 65447 => 'ᄃ',
+ 65448 => 'ᄄ',
+ 65449 => 'ᄅ',
+ 65450 => 'ᆰ',
+ 65451 => 'ᆱ',
+ 65452 => 'ᆲ',
+ 65453 => 'ᆳ',
+ 65454 => 'ᆴ',
+ 65455 => 'ᆵ',
+ 65456 => 'ᄚ',
+ 65457 => 'ᄆ',
+ 65458 => 'ᄇ',
+ 65459 => 'ᄈ',
+ 65460 => 'ᄡ',
+ 65461 => 'ᄉ',
+ 65462 => 'ᄊ',
+ 65463 => 'ᄋ',
+ 65464 => 'ᄌ',
+ 65465 => 'ᄍ',
+ 65466 => 'ᄎ',
+ 65467 => 'ᄏ',
+ 65468 => 'ᄐ',
+ 65469 => 'ᄑ',
+ 65470 => 'ᄒ',
+ 65474 => 'ᅡ',
+ 65475 => 'ᅢ',
+ 65476 => 'ᅣ',
+ 65477 => 'ᅤ',
+ 65478 => 'ᅥ',
+ 65479 => 'ᅦ',
+ 65482 => 'ᅧ',
+ 65483 => 'ᅨ',
+ 65484 => 'ᅩ',
+ 65485 => 'ᅪ',
+ 65486 => 'ᅫ',
+ 65487 => 'ᅬ',
+ 65490 => 'ᅭ',
+ 65491 => 'ᅮ',
+ 65492 => 'ᅯ',
+ 65493 => 'ᅰ',
+ 65494 => 'ᅱ',
+ 65495 => 'ᅲ',
+ 65498 => 'ᅳ',
+ 65499 => 'ᅴ',
+ 65500 => 'ᅵ',
+ 65504 => '¢',
+ 65505 => '£',
+ 65506 => '¬',
+ 65508 => '¦',
+ 65509 => '¥',
+ 65510 => '₩',
+ 65512 => '│',
+ 65513 => '←',
+ 65514 => '↑',
+ 65515 => '→',
+ 65516 => '↓',
+ 65517 => '■',
+ 65518 => '○',
+ 66560 => '𐐨',
+ 66561 => '𐐩',
+ 66562 => '𐐪',
+ 66563 => '𐐫',
+ 66564 => '𐐬',
+ 66565 => '𐐭',
+ 66566 => '𐐮',
+ 66567 => '𐐯',
+ 66568 => '𐐰',
+ 66569 => '𐐱',
+ 66570 => '𐐲',
+ 66571 => '𐐳',
+ 66572 => '𐐴',
+ 66573 => '𐐵',
+ 66574 => '𐐶',
+ 66575 => '𐐷',
+ 66576 => '𐐸',
+ 66577 => '𐐹',
+ 66578 => '𐐺',
+ 66579 => '𐐻',
+ 66580 => '𐐼',
+ 66581 => '𐐽',
+ 66582 => '𐐾',
+ 66583 => '𐐿',
+ 66584 => '𐑀',
+ 66585 => '𐑁',
+ 66586 => '𐑂',
+ 66587 => '𐑃',
+ 66588 => '𐑄',
+ 66589 => '𐑅',
+ 66590 => '𐑆',
+ 66591 => '𐑇',
+ 66592 => '𐑈',
+ 66593 => '𐑉',
+ 66594 => '𐑊',
+ 66595 => '𐑋',
+ 66596 => '𐑌',
+ 66597 => '𐑍',
+ 66598 => '𐑎',
+ 66599 => '𐑏',
+ 66736 => '𐓘',
+ 66737 => '𐓙',
+ 66738 => '𐓚',
+ 66739 => '𐓛',
+ 66740 => '𐓜',
+ 66741 => '𐓝',
+ 66742 => '𐓞',
+ 66743 => '𐓟',
+ 66744 => '𐓠',
+ 66745 => '𐓡',
+ 66746 => '𐓢',
+ 66747 => '𐓣',
+ 66748 => '𐓤',
+ 66749 => '𐓥',
+ 66750 => '𐓦',
+ 66751 => '𐓧',
+ 66752 => '𐓨',
+ 66753 => '𐓩',
+ 66754 => '𐓪',
+ 66755 => '𐓫',
+ 66756 => '𐓬',
+ 66757 => '𐓭',
+ 66758 => '𐓮',
+ 66759 => '𐓯',
+ 66760 => '𐓰',
+ 66761 => '𐓱',
+ 66762 => '𐓲',
+ 66763 => '𐓳',
+ 66764 => '𐓴',
+ 66765 => '𐓵',
+ 66766 => '𐓶',
+ 66767 => '𐓷',
+ 66768 => '𐓸',
+ 66769 => '𐓹',
+ 66770 => '𐓺',
+ 66771 => '𐓻',
+ 68736 => '𐳀',
+ 68737 => '𐳁',
+ 68738 => '𐳂',
+ 68739 => '𐳃',
+ 68740 => '𐳄',
+ 68741 => '𐳅',
+ 68742 => '𐳆',
+ 68743 => '𐳇',
+ 68744 => '𐳈',
+ 68745 => '𐳉',
+ 68746 => '𐳊',
+ 68747 => '𐳋',
+ 68748 => '𐳌',
+ 68749 => '𐳍',
+ 68750 => '𐳎',
+ 68751 => '𐳏',
+ 68752 => '𐳐',
+ 68753 => '𐳑',
+ 68754 => '𐳒',
+ 68755 => '𐳓',
+ 68756 => '𐳔',
+ 68757 => '𐳕',
+ 68758 => '𐳖',
+ 68759 => '𐳗',
+ 68760 => '𐳘',
+ 68761 => '𐳙',
+ 68762 => '𐳚',
+ 68763 => '𐳛',
+ 68764 => '𐳜',
+ 68765 => '𐳝',
+ 68766 => '𐳞',
+ 68767 => '𐳟',
+ 68768 => '𐳠',
+ 68769 => '𐳡',
+ 68770 => '𐳢',
+ 68771 => '𐳣',
+ 68772 => '𐳤',
+ 68773 => '𐳥',
+ 68774 => '𐳦',
+ 68775 => '𐳧',
+ 68776 => '𐳨',
+ 68777 => '𐳩',
+ 68778 => '𐳪',
+ 68779 => '𐳫',
+ 68780 => '𐳬',
+ 68781 => '𐳭',
+ 68782 => '𐳮',
+ 68783 => '𐳯',
+ 68784 => '𐳰',
+ 68785 => '𐳱',
+ 68786 => '𐳲',
+ 71840 => '𑣀',
+ 71841 => '𑣁',
+ 71842 => '𑣂',
+ 71843 => '𑣃',
+ 71844 => '𑣄',
+ 71845 => '𑣅',
+ 71846 => '𑣆',
+ 71847 => '𑣇',
+ 71848 => '𑣈',
+ 71849 => '𑣉',
+ 71850 => '𑣊',
+ 71851 => '𑣋',
+ 71852 => '𑣌',
+ 71853 => '𑣍',
+ 71854 => '𑣎',
+ 71855 => '𑣏',
+ 71856 => '𑣐',
+ 71857 => '𑣑',
+ 71858 => '𑣒',
+ 71859 => '𑣓',
+ 71860 => '𑣔',
+ 71861 => '𑣕',
+ 71862 => '𑣖',
+ 71863 => '𑣗',
+ 71864 => '𑣘',
+ 71865 => '𑣙',
+ 71866 => '𑣚',
+ 71867 => '𑣛',
+ 71868 => '𑣜',
+ 71869 => '𑣝',
+ 71870 => '𑣞',
+ 71871 => '𑣟',
+ 93760 => '𖹠',
+ 93761 => '𖹡',
+ 93762 => '𖹢',
+ 93763 => '𖹣',
+ 93764 => '𖹤',
+ 93765 => '𖹥',
+ 93766 => '𖹦',
+ 93767 => '𖹧',
+ 93768 => '𖹨',
+ 93769 => '𖹩',
+ 93770 => '𖹪',
+ 93771 => '𖹫',
+ 93772 => '𖹬',
+ 93773 => '𖹭',
+ 93774 => '𖹮',
+ 93775 => '𖹯',
+ 93776 => '𖹰',
+ 93777 => '𖹱',
+ 93778 => '𖹲',
+ 93779 => '𖹳',
+ 93780 => '𖹴',
+ 93781 => '𖹵',
+ 93782 => '𖹶',
+ 93783 => '𖹷',
+ 93784 => '𖹸',
+ 93785 => '𖹹',
+ 93786 => '𖹺',
+ 93787 => '𖹻',
+ 93788 => '𖹼',
+ 93789 => '𖹽',
+ 93790 => '𖹾',
+ 93791 => '𖹿',
+ 119134 => '𝅗𝅥',
+ 119135 => '𝅘𝅥',
+ 119136 => '𝅘𝅥𝅮',
+ 119137 => '𝅘𝅥𝅯',
+ 119138 => '𝅘𝅥𝅰',
+ 119139 => '𝅘𝅥𝅱',
+ 119140 => '𝅘𝅥𝅲',
+ 119227 => '𝆹𝅥',
+ 119228 => '𝆺𝅥',
+ 119229 => '𝆹𝅥𝅮',
+ 119230 => '𝆺𝅥𝅮',
+ 119231 => '𝆹𝅥𝅯',
+ 119232 => '𝆺𝅥𝅯',
+ 119808 => 'a',
+ 119809 => 'b',
+ 119810 => 'c',
+ 119811 => 'd',
+ 119812 => 'e',
+ 119813 => 'f',
+ 119814 => 'g',
+ 119815 => 'h',
+ 119816 => 'i',
+ 119817 => 'j',
+ 119818 => 'k',
+ 119819 => 'l',
+ 119820 => 'm',
+ 119821 => 'n',
+ 119822 => 'o',
+ 119823 => 'p',
+ 119824 => 'q',
+ 119825 => 'r',
+ 119826 => 's',
+ 119827 => 't',
+ 119828 => 'u',
+ 119829 => 'v',
+ 119830 => 'w',
+ 119831 => 'x',
+ 119832 => 'y',
+ 119833 => 'z',
+ 119834 => 'a',
+ 119835 => 'b',
+ 119836 => 'c',
+ 119837 => 'd',
+ 119838 => 'e',
+ 119839 => 'f',
+ 119840 => 'g',
+ 119841 => 'h',
+ 119842 => 'i',
+ 119843 => 'j',
+ 119844 => 'k',
+ 119845 => 'l',
+ 119846 => 'm',
+ 119847 => 'n',
+ 119848 => 'o',
+ 119849 => 'p',
+ 119850 => 'q',
+ 119851 => 'r',
+ 119852 => 's',
+ 119853 => 't',
+ 119854 => 'u',
+ 119855 => 'v',
+ 119856 => 'w',
+ 119857 => 'x',
+ 119858 => 'y',
+ 119859 => 'z',
+ 119860 => 'a',
+ 119861 => 'b',
+ 119862 => 'c',
+ 119863 => 'd',
+ 119864 => 'e',
+ 119865 => 'f',
+ 119866 => 'g',
+ 119867 => 'h',
+ 119868 => 'i',
+ 119869 => 'j',
+ 119870 => 'k',
+ 119871 => 'l',
+ 119872 => 'm',
+ 119873 => 'n',
+ 119874 => 'o',
+ 119875 => 'p',
+ 119876 => 'q',
+ 119877 => 'r',
+ 119878 => 's',
+ 119879 => 't',
+ 119880 => 'u',
+ 119881 => 'v',
+ 119882 => 'w',
+ 119883 => 'x',
+ 119884 => 'y',
+ 119885 => 'z',
+ 119886 => 'a',
+ 119887 => 'b',
+ 119888 => 'c',
+ 119889 => 'd',
+ 119890 => 'e',
+ 119891 => 'f',
+ 119892 => 'g',
+ 119894 => 'i',
+ 119895 => 'j',
+ 119896 => 'k',
+ 119897 => 'l',
+ 119898 => 'm',
+ 119899 => 'n',
+ 119900 => 'o',
+ 119901 => 'p',
+ 119902 => 'q',
+ 119903 => 'r',
+ 119904 => 's',
+ 119905 => 't',
+ 119906 => 'u',
+ 119907 => 'v',
+ 119908 => 'w',
+ 119909 => 'x',
+ 119910 => 'y',
+ 119911 => 'z',
+ 119912 => 'a',
+ 119913 => 'b',
+ 119914 => 'c',
+ 119915 => 'd',
+ 119916 => 'e',
+ 119917 => 'f',
+ 119918 => 'g',
+ 119919 => 'h',
+ 119920 => 'i',
+ 119921 => 'j',
+ 119922 => 'k',
+ 119923 => 'l',
+ 119924 => 'm',
+ 119925 => 'n',
+ 119926 => 'o',
+ 119927 => 'p',
+ 119928 => 'q',
+ 119929 => 'r',
+ 119930 => 's',
+ 119931 => 't',
+ 119932 => 'u',
+ 119933 => 'v',
+ 119934 => 'w',
+ 119935 => 'x',
+ 119936 => 'y',
+ 119937 => 'z',
+ 119938 => 'a',
+ 119939 => 'b',
+ 119940 => 'c',
+ 119941 => 'd',
+ 119942 => 'e',
+ 119943 => 'f',
+ 119944 => 'g',
+ 119945 => 'h',
+ 119946 => 'i',
+ 119947 => 'j',
+ 119948 => 'k',
+ 119949 => 'l',
+ 119950 => 'm',
+ 119951 => 'n',
+ 119952 => 'o',
+ 119953 => 'p',
+ 119954 => 'q',
+ 119955 => 'r',
+ 119956 => 's',
+ 119957 => 't',
+ 119958 => 'u',
+ 119959 => 'v',
+ 119960 => 'w',
+ 119961 => 'x',
+ 119962 => 'y',
+ 119963 => 'z',
+ 119964 => 'a',
+ 119966 => 'c',
+ 119967 => 'd',
+ 119970 => 'g',
+ 119973 => 'j',
+ 119974 => 'k',
+ 119977 => 'n',
+ 119978 => 'o',
+ 119979 => 'p',
+ 119980 => 'q',
+ 119982 => 's',
+ 119983 => 't',
+ 119984 => 'u',
+ 119985 => 'v',
+ 119986 => 'w',
+ 119987 => 'x',
+ 119988 => 'y',
+ 119989 => 'z',
+ 119990 => 'a',
+ 119991 => 'b',
+ 119992 => 'c',
+ 119993 => 'd',
+ 119995 => 'f',
+ 119997 => 'h',
+ 119998 => 'i',
+ 119999 => 'j',
+ 120000 => 'k',
+ 120001 => 'l',
+ 120002 => 'm',
+ 120003 => 'n',
+ 120005 => 'p',
+ 120006 => 'q',
+ 120007 => 'r',
+ 120008 => 's',
+ 120009 => 't',
+ 120010 => 'u',
+ 120011 => 'v',
+ 120012 => 'w',
+ 120013 => 'x',
+ 120014 => 'y',
+ 120015 => 'z',
+ 120016 => 'a',
+ 120017 => 'b',
+ 120018 => 'c',
+ 120019 => 'd',
+ 120020 => 'e',
+ 120021 => 'f',
+ 120022 => 'g',
+ 120023 => 'h',
+ 120024 => 'i',
+ 120025 => 'j',
+ 120026 => 'k',
+ 120027 => 'l',
+ 120028 => 'm',
+ 120029 => 'n',
+ 120030 => 'o',
+ 120031 => 'p',
+ 120032 => 'q',
+ 120033 => 'r',
+ 120034 => 's',
+ 120035 => 't',
+ 120036 => 'u',
+ 120037 => 'v',
+ 120038 => 'w',
+ 120039 => 'x',
+ 120040 => 'y',
+ 120041 => 'z',
+ 120042 => 'a',
+ 120043 => 'b',
+ 120044 => 'c',
+ 120045 => 'd',
+ 120046 => 'e',
+ 120047 => 'f',
+ 120048 => 'g',
+ 120049 => 'h',
+ 120050 => 'i',
+ 120051 => 'j',
+ 120052 => 'k',
+ 120053 => 'l',
+ 120054 => 'm',
+ 120055 => 'n',
+ 120056 => 'o',
+ 120057 => 'p',
+ 120058 => 'q',
+ 120059 => 'r',
+ 120060 => 's',
+ 120061 => 't',
+ 120062 => 'u',
+ 120063 => 'v',
+ 120064 => 'w',
+ 120065 => 'x',
+ 120066 => 'y',
+ 120067 => 'z',
+ 120068 => 'a',
+ 120069 => 'b',
+ 120071 => 'd',
+ 120072 => 'e',
+ 120073 => 'f',
+ 120074 => 'g',
+ 120077 => 'j',
+ 120078 => 'k',
+ 120079 => 'l',
+ 120080 => 'm',
+ 120081 => 'n',
+ 120082 => 'o',
+ 120083 => 'p',
+ 120084 => 'q',
+ 120086 => 's',
+ 120087 => 't',
+ 120088 => 'u',
+ 120089 => 'v',
+ 120090 => 'w',
+ 120091 => 'x',
+ 120092 => 'y',
+ 120094 => 'a',
+ 120095 => 'b',
+ 120096 => 'c',
+ 120097 => 'd',
+ 120098 => 'e',
+ 120099 => 'f',
+ 120100 => 'g',
+ 120101 => 'h',
+ 120102 => 'i',
+ 120103 => 'j',
+ 120104 => 'k',
+ 120105 => 'l',
+ 120106 => 'm',
+ 120107 => 'n',
+ 120108 => 'o',
+ 120109 => 'p',
+ 120110 => 'q',
+ 120111 => 'r',
+ 120112 => 's',
+ 120113 => 't',
+ 120114 => 'u',
+ 120115 => 'v',
+ 120116 => 'w',
+ 120117 => 'x',
+ 120118 => 'y',
+ 120119 => 'z',
+ 120120 => 'a',
+ 120121 => 'b',
+ 120123 => 'd',
+ 120124 => 'e',
+ 120125 => 'f',
+ 120126 => 'g',
+ 120128 => 'i',
+ 120129 => 'j',
+ 120130 => 'k',
+ 120131 => 'l',
+ 120132 => 'm',
+ 120134 => 'o',
+ 120138 => 's',
+ 120139 => 't',
+ 120140 => 'u',
+ 120141 => 'v',
+ 120142 => 'w',
+ 120143 => 'x',
+ 120144 => 'y',
+ 120146 => 'a',
+ 120147 => 'b',
+ 120148 => 'c',
+ 120149 => 'd',
+ 120150 => 'e',
+ 120151 => 'f',
+ 120152 => 'g',
+ 120153 => 'h',
+ 120154 => 'i',
+ 120155 => 'j',
+ 120156 => 'k',
+ 120157 => 'l',
+ 120158 => 'm',
+ 120159 => 'n',
+ 120160 => 'o',
+ 120161 => 'p',
+ 120162 => 'q',
+ 120163 => 'r',
+ 120164 => 's',
+ 120165 => 't',
+ 120166 => 'u',
+ 120167 => 'v',
+ 120168 => 'w',
+ 120169 => 'x',
+ 120170 => 'y',
+ 120171 => 'z',
+ 120172 => 'a',
+ 120173 => 'b',
+ 120174 => 'c',
+ 120175 => 'd',
+ 120176 => 'e',
+ 120177 => 'f',
+ 120178 => 'g',
+ 120179 => 'h',
+ 120180 => 'i',
+ 120181 => 'j',
+ 120182 => 'k',
+ 120183 => 'l',
+ 120184 => 'm',
+ 120185 => 'n',
+ 120186 => 'o',
+ 120187 => 'p',
+ 120188 => 'q',
+ 120189 => 'r',
+ 120190 => 's',
+ 120191 => 't',
+ 120192 => 'u',
+ 120193 => 'v',
+ 120194 => 'w',
+ 120195 => 'x',
+ 120196 => 'y',
+ 120197 => 'z',
+ 120198 => 'a',
+ 120199 => 'b',
+ 120200 => 'c',
+ 120201 => 'd',
+ 120202 => 'e',
+ 120203 => 'f',
+ 120204 => 'g',
+ 120205 => 'h',
+ 120206 => 'i',
+ 120207 => 'j',
+ 120208 => 'k',
+ 120209 => 'l',
+ 120210 => 'm',
+ 120211 => 'n',
+ 120212 => 'o',
+ 120213 => 'p',
+ 120214 => 'q',
+ 120215 => 'r',
+ 120216 => 's',
+ 120217 => 't',
+ 120218 => 'u',
+ 120219 => 'v',
+ 120220 => 'w',
+ 120221 => 'x',
+ 120222 => 'y',
+ 120223 => 'z',
+ 120224 => 'a',
+ 120225 => 'b',
+ 120226 => 'c',
+ 120227 => 'd',
+ 120228 => 'e',
+ 120229 => 'f',
+ 120230 => 'g',
+ 120231 => 'h',
+ 120232 => 'i',
+ 120233 => 'j',
+ 120234 => 'k',
+ 120235 => 'l',
+ 120236 => 'm',
+ 120237 => 'n',
+ 120238 => 'o',
+ 120239 => 'p',
+ 120240 => 'q',
+ 120241 => 'r',
+ 120242 => 's',
+ 120243 => 't',
+ 120244 => 'u',
+ 120245 => 'v',
+ 120246 => 'w',
+ 120247 => 'x',
+ 120248 => 'y',
+ 120249 => 'z',
+ 120250 => 'a',
+ 120251 => 'b',
+ 120252 => 'c',
+ 120253 => 'd',
+ 120254 => 'e',
+ 120255 => 'f',
+ 120256 => 'g',
+ 120257 => 'h',
+ 120258 => 'i',
+ 120259 => 'j',
+ 120260 => 'k',
+ 120261 => 'l',
+ 120262 => 'm',
+ 120263 => 'n',
+ 120264 => 'o',
+ 120265 => 'p',
+ 120266 => 'q',
+ 120267 => 'r',
+ 120268 => 's',
+ 120269 => 't',
+ 120270 => 'u',
+ 120271 => 'v',
+ 120272 => 'w',
+ 120273 => 'x',
+ 120274 => 'y',
+ 120275 => 'z',
+ 120276 => 'a',
+ 120277 => 'b',
+ 120278 => 'c',
+ 120279 => 'd',
+ 120280 => 'e',
+ 120281 => 'f',
+ 120282 => 'g',
+ 120283 => 'h',
+ 120284 => 'i',
+ 120285 => 'j',
+ 120286 => 'k',
+ 120287 => 'l',
+ 120288 => 'm',
+ 120289 => 'n',
+ 120290 => 'o',
+ 120291 => 'p',
+ 120292 => 'q',
+ 120293 => 'r',
+ 120294 => 's',
+ 120295 => 't',
+ 120296 => 'u',
+ 120297 => 'v',
+ 120298 => 'w',
+ 120299 => 'x',
+ 120300 => 'y',
+ 120301 => 'z',
+ 120302 => 'a',
+ 120303 => 'b',
+ 120304 => 'c',
+ 120305 => 'd',
+ 120306 => 'e',
+ 120307 => 'f',
+ 120308 => 'g',
+ 120309 => 'h',
+ 120310 => 'i',
+ 120311 => 'j',
+ 120312 => 'k',
+ 120313 => 'l',
+ 120314 => 'm',
+ 120315 => 'n',
+ 120316 => 'o',
+ 120317 => 'p',
+ 120318 => 'q',
+ 120319 => 'r',
+ 120320 => 's',
+ 120321 => 't',
+ 120322 => 'u',
+ 120323 => 'v',
+ 120324 => 'w',
+ 120325 => 'x',
+ 120326 => 'y',
+ 120327 => 'z',
+ 120328 => 'a',
+ 120329 => 'b',
+ 120330 => 'c',
+ 120331 => 'd',
+ 120332 => 'e',
+ 120333 => 'f',
+ 120334 => 'g',
+ 120335 => 'h',
+ 120336 => 'i',
+ 120337 => 'j',
+ 120338 => 'k',
+ 120339 => 'l',
+ 120340 => 'm',
+ 120341 => 'n',
+ 120342 => 'o',
+ 120343 => 'p',
+ 120344 => 'q',
+ 120345 => 'r',
+ 120346 => 's',
+ 120347 => 't',
+ 120348 => 'u',
+ 120349 => 'v',
+ 120350 => 'w',
+ 120351 => 'x',
+ 120352 => 'y',
+ 120353 => 'z',
+ 120354 => 'a',
+ 120355 => 'b',
+ 120356 => 'c',
+ 120357 => 'd',
+ 120358 => 'e',
+ 120359 => 'f',
+ 120360 => 'g',
+ 120361 => 'h',
+ 120362 => 'i',
+ 120363 => 'j',
+ 120364 => 'k',
+ 120365 => 'l',
+ 120366 => 'm',
+ 120367 => 'n',
+ 120368 => 'o',
+ 120369 => 'p',
+ 120370 => 'q',
+ 120371 => 'r',
+ 120372 => 's',
+ 120373 => 't',
+ 120374 => 'u',
+ 120375 => 'v',
+ 120376 => 'w',
+ 120377 => 'x',
+ 120378 => 'y',
+ 120379 => 'z',
+ 120380 => 'a',
+ 120381 => 'b',
+ 120382 => 'c',
+ 120383 => 'd',
+ 120384 => 'e',
+ 120385 => 'f',
+ 120386 => 'g',
+ 120387 => 'h',
+ 120388 => 'i',
+ 120389 => 'j',
+ 120390 => 'k',
+ 120391 => 'l',
+ 120392 => 'm',
+ 120393 => 'n',
+ 120394 => 'o',
+ 120395 => 'p',
+ 120396 => 'q',
+ 120397 => 'r',
+ 120398 => 's',
+ 120399 => 't',
+ 120400 => 'u',
+ 120401 => 'v',
+ 120402 => 'w',
+ 120403 => 'x',
+ 120404 => 'y',
+ 120405 => 'z',
+ 120406 => 'a',
+ 120407 => 'b',
+ 120408 => 'c',
+ 120409 => 'd',
+ 120410 => 'e',
+ 120411 => 'f',
+ 120412 => 'g',
+ 120413 => 'h',
+ 120414 => 'i',
+ 120415 => 'j',
+ 120416 => 'k',
+ 120417 => 'l',
+ 120418 => 'm',
+ 120419 => 'n',
+ 120420 => 'o',
+ 120421 => 'p',
+ 120422 => 'q',
+ 120423 => 'r',
+ 120424 => 's',
+ 120425 => 't',
+ 120426 => 'u',
+ 120427 => 'v',
+ 120428 => 'w',
+ 120429 => 'x',
+ 120430 => 'y',
+ 120431 => 'z',
+ 120432 => 'a',
+ 120433 => 'b',
+ 120434 => 'c',
+ 120435 => 'd',
+ 120436 => 'e',
+ 120437 => 'f',
+ 120438 => 'g',
+ 120439 => 'h',
+ 120440 => 'i',
+ 120441 => 'j',
+ 120442 => 'k',
+ 120443 => 'l',
+ 120444 => 'm',
+ 120445 => 'n',
+ 120446 => 'o',
+ 120447 => 'p',
+ 120448 => 'q',
+ 120449 => 'r',
+ 120450 => 's',
+ 120451 => 't',
+ 120452 => 'u',
+ 120453 => 'v',
+ 120454 => 'w',
+ 120455 => 'x',
+ 120456 => 'y',
+ 120457 => 'z',
+ 120458 => 'a',
+ 120459 => 'b',
+ 120460 => 'c',
+ 120461 => 'd',
+ 120462 => 'e',
+ 120463 => 'f',
+ 120464 => 'g',
+ 120465 => 'h',
+ 120466 => 'i',
+ 120467 => 'j',
+ 120468 => 'k',
+ 120469 => 'l',
+ 120470 => 'm',
+ 120471 => 'n',
+ 120472 => 'o',
+ 120473 => 'p',
+ 120474 => 'q',
+ 120475 => 'r',
+ 120476 => 's',
+ 120477 => 't',
+ 120478 => 'u',
+ 120479 => 'v',
+ 120480 => 'w',
+ 120481 => 'x',
+ 120482 => 'y',
+ 120483 => 'z',
+ 120484 => 'ı',
+ 120485 => 'ȷ',
+ 120488 => 'α',
+ 120489 => 'β',
+ 120490 => 'γ',
+ 120491 => 'δ',
+ 120492 => 'ε',
+ 120493 => 'ζ',
+ 120494 => 'η',
+ 120495 => 'θ',
+ 120496 => 'ι',
+ 120497 => 'κ',
+ 120498 => 'λ',
+ 120499 => 'μ',
+ 120500 => 'ν',
+ 120501 => 'ξ',
+ 120502 => 'ο',
+ 120503 => 'π',
+ 120504 => 'ρ',
+ 120505 => 'θ',
+ 120506 => 'σ',
+ 120507 => 'τ',
+ 120508 => 'υ',
+ 120509 => 'φ',
+ 120510 => 'χ',
+ 120511 => 'ψ',
+ 120512 => 'ω',
+ 120513 => '∇',
+ 120514 => 'α',
+ 120515 => 'β',
+ 120516 => 'γ',
+ 120517 => 'δ',
+ 120518 => 'ε',
+ 120519 => 'ζ',
+ 120520 => 'η',
+ 120521 => 'θ',
+ 120522 => 'ι',
+ 120523 => 'κ',
+ 120524 => 'λ',
+ 120525 => 'μ',
+ 120526 => 'ν',
+ 120527 => 'ξ',
+ 120528 => 'ο',
+ 120529 => 'π',
+ 120530 => 'ρ',
+ 120531 => 'σ',
+ 120532 => 'σ',
+ 120533 => 'τ',
+ 120534 => 'υ',
+ 120535 => 'φ',
+ 120536 => 'χ',
+ 120537 => 'ψ',
+ 120538 => 'ω',
+ 120539 => '∂',
+ 120540 => 'ε',
+ 120541 => 'θ',
+ 120542 => 'κ',
+ 120543 => 'φ',
+ 120544 => 'ρ',
+ 120545 => 'π',
+ 120546 => 'α',
+ 120547 => 'β',
+ 120548 => 'γ',
+ 120549 => 'δ',
+ 120550 => 'ε',
+ 120551 => 'ζ',
+ 120552 => 'η',
+ 120553 => 'θ',
+ 120554 => 'ι',
+ 120555 => 'κ',
+ 120556 => 'λ',
+ 120557 => 'μ',
+ 120558 => 'ν',
+ 120559 => 'ξ',
+ 120560 => 'ο',
+ 120561 => 'π',
+ 120562 => 'ρ',
+ 120563 => 'θ',
+ 120564 => 'σ',
+ 120565 => 'τ',
+ 120566 => 'υ',
+ 120567 => 'φ',
+ 120568 => 'χ',
+ 120569 => 'ψ',
+ 120570 => 'ω',
+ 120571 => '∇',
+ 120572 => 'α',
+ 120573 => 'β',
+ 120574 => 'γ',
+ 120575 => 'δ',
+ 120576 => 'ε',
+ 120577 => 'ζ',
+ 120578 => 'η',
+ 120579 => 'θ',
+ 120580 => 'ι',
+ 120581 => 'κ',
+ 120582 => 'λ',
+ 120583 => 'μ',
+ 120584 => 'ν',
+ 120585 => 'ξ',
+ 120586 => 'ο',
+ 120587 => 'π',
+ 120588 => 'ρ',
+ 120589 => 'σ',
+ 120590 => 'σ',
+ 120591 => 'τ',
+ 120592 => 'υ',
+ 120593 => 'φ',
+ 120594 => 'χ',
+ 120595 => 'ψ',
+ 120596 => 'ω',
+ 120597 => '∂',
+ 120598 => 'ε',
+ 120599 => 'θ',
+ 120600 => 'κ',
+ 120601 => 'φ',
+ 120602 => 'ρ',
+ 120603 => 'π',
+ 120604 => 'α',
+ 120605 => 'β',
+ 120606 => 'γ',
+ 120607 => 'δ',
+ 120608 => 'ε',
+ 120609 => 'ζ',
+ 120610 => 'η',
+ 120611 => 'θ',
+ 120612 => 'ι',
+ 120613 => 'κ',
+ 120614 => 'λ',
+ 120615 => 'μ',
+ 120616 => 'ν',
+ 120617 => 'ξ',
+ 120618 => 'ο',
+ 120619 => 'π',
+ 120620 => 'ρ',
+ 120621 => 'θ',
+ 120622 => 'σ',
+ 120623 => 'τ',
+ 120624 => 'υ',
+ 120625 => 'φ',
+ 120626 => 'χ',
+ 120627 => 'ψ',
+ 120628 => 'ω',
+ 120629 => '∇',
+ 120630 => 'α',
+ 120631 => 'β',
+ 120632 => 'γ',
+ 120633 => 'δ',
+ 120634 => 'ε',
+ 120635 => 'ζ',
+ 120636 => 'η',
+ 120637 => 'θ',
+ 120638 => 'ι',
+ 120639 => 'κ',
+ 120640 => 'λ',
+ 120641 => 'μ',
+ 120642 => 'ν',
+ 120643 => 'ξ',
+ 120644 => 'ο',
+ 120645 => 'π',
+ 120646 => 'ρ',
+ 120647 => 'σ',
+ 120648 => 'σ',
+ 120649 => 'τ',
+ 120650 => 'υ',
+ 120651 => 'φ',
+ 120652 => 'χ',
+ 120653 => 'ψ',
+ 120654 => 'ω',
+ 120655 => '∂',
+ 120656 => 'ε',
+ 120657 => 'θ',
+ 120658 => 'κ',
+ 120659 => 'φ',
+ 120660 => 'ρ',
+ 120661 => 'π',
+ 120662 => 'α',
+ 120663 => 'β',
+ 120664 => 'γ',
+ 120665 => 'δ',
+ 120666 => 'ε',
+ 120667 => 'ζ',
+ 120668 => 'η',
+ 120669 => 'θ',
+ 120670 => 'ι',
+ 120671 => 'κ',
+ 120672 => 'λ',
+ 120673 => 'μ',
+ 120674 => 'ν',
+ 120675 => 'ξ',
+ 120676 => 'ο',
+ 120677 => 'π',
+ 120678 => 'ρ',
+ 120679 => 'θ',
+ 120680 => 'σ',
+ 120681 => 'τ',
+ 120682 => 'υ',
+ 120683 => 'φ',
+ 120684 => 'χ',
+ 120685 => 'ψ',
+ 120686 => 'ω',
+ 120687 => '∇',
+ 120688 => 'α',
+ 120689 => 'β',
+ 120690 => 'γ',
+ 120691 => 'δ',
+ 120692 => 'ε',
+ 120693 => 'ζ',
+ 120694 => 'η',
+ 120695 => 'θ',
+ 120696 => 'ι',
+ 120697 => 'κ',
+ 120698 => 'λ',
+ 120699 => 'μ',
+ 120700 => 'ν',
+ 120701 => 'ξ',
+ 120702 => 'ο',
+ 120703 => 'π',
+ 120704 => 'ρ',
+ 120705 => 'σ',
+ 120706 => 'σ',
+ 120707 => 'τ',
+ 120708 => 'υ',
+ 120709 => 'φ',
+ 120710 => 'χ',
+ 120711 => 'ψ',
+ 120712 => 'ω',
+ 120713 => '∂',
+ 120714 => 'ε',
+ 120715 => 'θ',
+ 120716 => 'κ',
+ 120717 => 'φ',
+ 120718 => 'ρ',
+ 120719 => 'π',
+ 120720 => 'α',
+ 120721 => 'β',
+ 120722 => 'γ',
+ 120723 => 'δ',
+ 120724 => 'ε',
+ 120725 => 'ζ',
+ 120726 => 'η',
+ 120727 => 'θ',
+ 120728 => 'ι',
+ 120729 => 'κ',
+ 120730 => 'λ',
+ 120731 => 'μ',
+ 120732 => 'ν',
+ 120733 => 'ξ',
+ 120734 => 'ο',
+ 120735 => 'π',
+ 120736 => 'ρ',
+ 120737 => 'θ',
+ 120738 => 'σ',
+ 120739 => 'τ',
+ 120740 => 'υ',
+ 120741 => 'φ',
+ 120742 => 'χ',
+ 120743 => 'ψ',
+ 120744 => 'ω',
+ 120745 => '∇',
+ 120746 => 'α',
+ 120747 => 'β',
+ 120748 => 'γ',
+ 120749 => 'δ',
+ 120750 => 'ε',
+ 120751 => 'ζ',
+ 120752 => 'η',
+ 120753 => 'θ',
+ 120754 => 'ι',
+ 120755 => 'κ',
+ 120756 => 'λ',
+ 120757 => 'μ',
+ 120758 => 'ν',
+ 120759 => 'ξ',
+ 120760 => 'ο',
+ 120761 => 'π',
+ 120762 => 'ρ',
+ 120763 => 'σ',
+ 120764 => 'σ',
+ 120765 => 'τ',
+ 120766 => 'υ',
+ 120767 => 'φ',
+ 120768 => 'χ',
+ 120769 => 'ψ',
+ 120770 => 'ω',
+ 120771 => '∂',
+ 120772 => 'ε',
+ 120773 => 'θ',
+ 120774 => 'κ',
+ 120775 => 'φ',
+ 120776 => 'ρ',
+ 120777 => 'π',
+ 120778 => 'ϝ',
+ 120779 => 'ϝ',
+ 120782 => '0',
+ 120783 => '1',
+ 120784 => '2',
+ 120785 => '3',
+ 120786 => '4',
+ 120787 => '5',
+ 120788 => '6',
+ 120789 => '7',
+ 120790 => '8',
+ 120791 => '9',
+ 120792 => '0',
+ 120793 => '1',
+ 120794 => '2',
+ 120795 => '3',
+ 120796 => '4',
+ 120797 => '5',
+ 120798 => '6',
+ 120799 => '7',
+ 120800 => '8',
+ 120801 => '9',
+ 120802 => '0',
+ 120803 => '1',
+ 120804 => '2',
+ 120805 => '3',
+ 120806 => '4',
+ 120807 => '5',
+ 120808 => '6',
+ 120809 => '7',
+ 120810 => '8',
+ 120811 => '9',
+ 120812 => '0',
+ 120813 => '1',
+ 120814 => '2',
+ 120815 => '3',
+ 120816 => '4',
+ 120817 => '5',
+ 120818 => '6',
+ 120819 => '7',
+ 120820 => '8',
+ 120821 => '9',
+ 120822 => '0',
+ 120823 => '1',
+ 120824 => '2',
+ 120825 => '3',
+ 120826 => '4',
+ 120827 => '5',
+ 120828 => '6',
+ 120829 => '7',
+ 120830 => '8',
+ 120831 => '9',
+ 125184 => '𞤢',
+ 125185 => '𞤣',
+ 125186 => '𞤤',
+ 125187 => '𞤥',
+ 125188 => '𞤦',
+ 125189 => '𞤧',
+ 125190 => '𞤨',
+ 125191 => '𞤩',
+ 125192 => '𞤪',
+ 125193 => '𞤫',
+ 125194 => '𞤬',
+ 125195 => '𞤭',
+ 125196 => '𞤮',
+ 125197 => '𞤯',
+ 125198 => '𞤰',
+ 125199 => '𞤱',
+ 125200 => '𞤲',
+ 125201 => '𞤳',
+ 125202 => '𞤴',
+ 125203 => '𞤵',
+ 125204 => '𞤶',
+ 125205 => '𞤷',
+ 125206 => '𞤸',
+ 125207 => '𞤹',
+ 125208 => '𞤺',
+ 125209 => '𞤻',
+ 125210 => '𞤼',
+ 125211 => '𞤽',
+ 125212 => '𞤾',
+ 125213 => '𞤿',
+ 125214 => '𞥀',
+ 125215 => '𞥁',
+ 125216 => '𞥂',
+ 125217 => '𞥃',
+ 126464 => 'ا',
+ 126465 => 'ب',
+ 126466 => 'ج',
+ 126467 => 'د',
+ 126469 => 'و',
+ 126470 => 'ز',
+ 126471 => 'ح',
+ 126472 => 'ط',
+ 126473 => 'ي',
+ 126474 => 'ك',
+ 126475 => 'ل',
+ 126476 => 'م',
+ 126477 => 'ن',
+ 126478 => 'س',
+ 126479 => 'ع',
+ 126480 => 'ف',
+ 126481 => 'ص',
+ 126482 => 'ق',
+ 126483 => 'ر',
+ 126484 => 'ش',
+ 126485 => 'ت',
+ 126486 => 'ث',
+ 126487 => 'خ',
+ 126488 => 'ذ',
+ 126489 => 'ض',
+ 126490 => 'ظ',
+ 126491 => 'غ',
+ 126492 => 'ٮ',
+ 126493 => 'ں',
+ 126494 => 'ڡ',
+ 126495 => 'ٯ',
+ 126497 => 'ب',
+ 126498 => 'ج',
+ 126500 => 'ه',
+ 126503 => 'ح',
+ 126505 => 'ي',
+ 126506 => 'ك',
+ 126507 => 'ل',
+ 126508 => 'م',
+ 126509 => 'ن',
+ 126510 => 'س',
+ 126511 => 'ع',
+ 126512 => 'ف',
+ 126513 => 'ص',
+ 126514 => 'ق',
+ 126516 => 'ش',
+ 126517 => 'ت',
+ 126518 => 'ث',
+ 126519 => 'خ',
+ 126521 => 'ض',
+ 126523 => 'غ',
+ 126530 => 'ج',
+ 126535 => 'ح',
+ 126537 => 'ي',
+ 126539 => 'ل',
+ 126541 => 'ن',
+ 126542 => 'س',
+ 126543 => 'ع',
+ 126545 => 'ص',
+ 126546 => 'ق',
+ 126548 => 'ش',
+ 126551 => 'خ',
+ 126553 => 'ض',
+ 126555 => 'غ',
+ 126557 => 'ں',
+ 126559 => 'ٯ',
+ 126561 => 'ب',
+ 126562 => 'ج',
+ 126564 => 'ه',
+ 126567 => 'ح',
+ 126568 => 'ط',
+ 126569 => 'ي',
+ 126570 => 'ك',
+ 126572 => 'م',
+ 126573 => 'ن',
+ 126574 => 'س',
+ 126575 => 'ع',
+ 126576 => 'ف',
+ 126577 => 'ص',
+ 126578 => 'ق',
+ 126580 => 'ش',
+ 126581 => 'ت',
+ 126582 => 'ث',
+ 126583 => 'خ',
+ 126585 => 'ض',
+ 126586 => 'ظ',
+ 126587 => 'غ',
+ 126588 => 'ٮ',
+ 126590 => 'ڡ',
+ 126592 => 'ا',
+ 126593 => 'ب',
+ 126594 => 'ج',
+ 126595 => 'د',
+ 126596 => 'ه',
+ 126597 => 'و',
+ 126598 => 'ز',
+ 126599 => 'ح',
+ 126600 => 'ط',
+ 126601 => 'ي',
+ 126603 => 'ل',
+ 126604 => 'م',
+ 126605 => 'ن',
+ 126606 => 'س',
+ 126607 => 'ع',
+ 126608 => 'ف',
+ 126609 => 'ص',
+ 126610 => 'ق',
+ 126611 => 'ر',
+ 126612 => 'ش',
+ 126613 => 'ت',
+ 126614 => 'ث',
+ 126615 => 'خ',
+ 126616 => 'ذ',
+ 126617 => 'ض',
+ 126618 => 'ظ',
+ 126619 => 'غ',
+ 126625 => 'ب',
+ 126626 => 'ج',
+ 126627 => 'د',
+ 126629 => 'و',
+ 126630 => 'ز',
+ 126631 => 'ح',
+ 126632 => 'ط',
+ 126633 => 'ي',
+ 126635 => 'ل',
+ 126636 => 'م',
+ 126637 => 'ن',
+ 126638 => 'س',
+ 126639 => 'ع',
+ 126640 => 'ف',
+ 126641 => 'ص',
+ 126642 => 'ق',
+ 126643 => 'ر',
+ 126644 => 'ش',
+ 126645 => 'ت',
+ 126646 => 'ث',
+ 126647 => 'خ',
+ 126648 => 'ذ',
+ 126649 => 'ض',
+ 126650 => 'ظ',
+ 126651 => 'غ',
+ 127274 => '〔s〕',
+ 127275 => 'c',
+ 127276 => 'r',
+ 127277 => 'cd',
+ 127278 => 'wz',
+ 127280 => 'a',
+ 127281 => 'b',
+ 127282 => 'c',
+ 127283 => 'd',
+ 127284 => 'e',
+ 127285 => 'f',
+ 127286 => 'g',
+ 127287 => 'h',
+ 127288 => 'i',
+ 127289 => 'j',
+ 127290 => 'k',
+ 127291 => 'l',
+ 127292 => 'm',
+ 127293 => 'n',
+ 127294 => 'o',
+ 127295 => 'p',
+ 127296 => 'q',
+ 127297 => 'r',
+ 127298 => 's',
+ 127299 => 't',
+ 127300 => 'u',
+ 127301 => 'v',
+ 127302 => 'w',
+ 127303 => 'x',
+ 127304 => 'y',
+ 127305 => 'z',
+ 127306 => 'hv',
+ 127307 => 'mv',
+ 127308 => 'sd',
+ 127309 => 'ss',
+ 127310 => 'ppv',
+ 127311 => 'wc',
+ 127338 => 'mc',
+ 127339 => 'md',
+ 127340 => 'mr',
+ 127376 => 'dj',
+ 127488 => 'ほか',
+ 127489 => 'ココ',
+ 127490 => 'サ',
+ 127504 => '手',
+ 127505 => '字',
+ 127506 => '双',
+ 127507 => 'デ',
+ 127508 => '二',
+ 127509 => '多',
+ 127510 => '解',
+ 127511 => '天',
+ 127512 => '交',
+ 127513 => '映',
+ 127514 => '無',
+ 127515 => '料',
+ 127516 => '前',
+ 127517 => '後',
+ 127518 => '再',
+ 127519 => '新',
+ 127520 => '初',
+ 127521 => '終',
+ 127522 => '生',
+ 127523 => '販',
+ 127524 => '声',
+ 127525 => '吹',
+ 127526 => '演',
+ 127527 => '投',
+ 127528 => '捕',
+ 127529 => '一',
+ 127530 => '三',
+ 127531 => '遊',
+ 127532 => '左',
+ 127533 => '中',
+ 127534 => '右',
+ 127535 => '指',
+ 127536 => '走',
+ 127537 => '打',
+ 127538 => '禁',
+ 127539 => '空',
+ 127540 => '合',
+ 127541 => '満',
+ 127542 => '有',
+ 127543 => '月',
+ 127544 => '申',
+ 127545 => '割',
+ 127546 => '営',
+ 127547 => '配',
+ 127552 => '〔本〕',
+ 127553 => '〔三〕',
+ 127554 => '〔二〕',
+ 127555 => '〔安〕',
+ 127556 => '〔点〕',
+ 127557 => '〔打〕',
+ 127558 => '〔盗〕',
+ 127559 => '〔勝〕',
+ 127560 => '〔敗〕',
+ 127568 => '得',
+ 127569 => '可',
+ 130032 => '0',
+ 130033 => '1',
+ 130034 => '2',
+ 130035 => '3',
+ 130036 => '4',
+ 130037 => '5',
+ 130038 => '6',
+ 130039 => '7',
+ 130040 => '8',
+ 130041 => '9',
+ 194560 => '丽',
+ 194561 => '丸',
+ 194562 => '乁',
+ 194563 => '𠄢',
+ 194564 => '你',
+ 194565 => '侮',
+ 194566 => '侻',
+ 194567 => '倂',
+ 194568 => '偺',
+ 194569 => '備',
+ 194570 => '僧',
+ 194571 => '像',
+ 194572 => '㒞',
+ 194573 => '𠘺',
+ 194574 => '免',
+ 194575 => '兔',
+ 194576 => '兤',
+ 194577 => '具',
+ 194578 => '𠔜',
+ 194579 => '㒹',
+ 194580 => '內',
+ 194581 => '再',
+ 194582 => '𠕋',
+ 194583 => '冗',
+ 194584 => '冤',
+ 194585 => '仌',
+ 194586 => '冬',
+ 194587 => '况',
+ 194588 => '𩇟',
+ 194589 => '凵',
+ 194590 => '刃',
+ 194591 => '㓟',
+ 194592 => '刻',
+ 194593 => '剆',
+ 194594 => '割',
+ 194595 => '剷',
+ 194596 => '㔕',
+ 194597 => '勇',
+ 194598 => '勉',
+ 194599 => '勤',
+ 194600 => '勺',
+ 194601 => '包',
+ 194602 => '匆',
+ 194603 => '北',
+ 194604 => '卉',
+ 194605 => '卑',
+ 194606 => '博',
+ 194607 => '即',
+ 194608 => '卽',
+ 194609 => '卿',
+ 194610 => '卿',
+ 194611 => '卿',
+ 194612 => '𠨬',
+ 194613 => '灰',
+ 194614 => '及',
+ 194615 => '叟',
+ 194616 => '𠭣',
+ 194617 => '叫',
+ 194618 => '叱',
+ 194619 => '吆',
+ 194620 => '咞',
+ 194621 => '吸',
+ 194622 => '呈',
+ 194623 => '周',
+ 194624 => '咢',
+ 194625 => '哶',
+ 194626 => '唐',
+ 194627 => '啓',
+ 194628 => '啣',
+ 194629 => '善',
+ 194630 => '善',
+ 194631 => '喙',
+ 194632 => '喫',
+ 194633 => '喳',
+ 194634 => '嗂',
+ 194635 => '圖',
+ 194636 => '嘆',
+ 194637 => '圗',
+ 194638 => '噑',
+ 194639 => '噴',
+ 194640 => '切',
+ 194641 => '壮',
+ 194642 => '城',
+ 194643 => '埴',
+ 194644 => '堍',
+ 194645 => '型',
+ 194646 => '堲',
+ 194647 => '報',
+ 194648 => '墬',
+ 194649 => '𡓤',
+ 194650 => '売',
+ 194651 => '壷',
+ 194652 => '夆',
+ 194653 => '多',
+ 194654 => '夢',
+ 194655 => '奢',
+ 194656 => '𡚨',
+ 194657 => '𡛪',
+ 194658 => '姬',
+ 194659 => '娛',
+ 194660 => '娧',
+ 194661 => '姘',
+ 194662 => '婦',
+ 194663 => '㛮',
+ 194665 => '嬈',
+ 194666 => '嬾',
+ 194667 => '嬾',
+ 194668 => '𡧈',
+ 194669 => '寃',
+ 194670 => '寘',
+ 194671 => '寧',
+ 194672 => '寳',
+ 194673 => '𡬘',
+ 194674 => '寿',
+ 194675 => '将',
+ 194677 => '尢',
+ 194678 => '㞁',
+ 194679 => '屠',
+ 194680 => '屮',
+ 194681 => '峀',
+ 194682 => '岍',
+ 194683 => '𡷤',
+ 194684 => '嵃',
+ 194685 => '𡷦',
+ 194686 => '嵮',
+ 194687 => '嵫',
+ 194688 => '嵼',
+ 194689 => '巡',
+ 194690 => '巢',
+ 194691 => '㠯',
+ 194692 => '巽',
+ 194693 => '帨',
+ 194694 => '帽',
+ 194695 => '幩',
+ 194696 => '㡢',
+ 194697 => '𢆃',
+ 194698 => '㡼',
+ 194699 => '庰',
+ 194700 => '庳',
+ 194701 => '庶',
+ 194702 => '廊',
+ 194703 => '𪎒',
+ 194704 => '廾',
+ 194705 => '𢌱',
+ 194706 => '𢌱',
+ 194707 => '舁',
+ 194708 => '弢',
+ 194709 => '弢',
+ 194710 => '㣇',
+ 194711 => '𣊸',
+ 194712 => '𦇚',
+ 194713 => '形',
+ 194714 => '彫',
+ 194715 => '㣣',
+ 194716 => '徚',
+ 194717 => '忍',
+ 194718 => '志',
+ 194719 => '忹',
+ 194720 => '悁',
+ 194721 => '㤺',
+ 194722 => '㤜',
+ 194723 => '悔',
+ 194724 => '𢛔',
+ 194725 => '惇',
+ 194726 => '慈',
+ 194727 => '慌',
+ 194728 => '慎',
+ 194729 => '慌',
+ 194730 => '慺',
+ 194731 => '憎',
+ 194732 => '憲',
+ 194733 => '憤',
+ 194734 => '憯',
+ 194735 => '懞',
+ 194736 => '懲',
+ 194737 => '懶',
+ 194738 => '成',
+ 194739 => '戛',
+ 194740 => '扝',
+ 194741 => '抱',
+ 194742 => '拔',
+ 194743 => '捐',
+ 194744 => '𢬌',
+ 194745 => '挽',
+ 194746 => '拼',
+ 194747 => '捨',
+ 194748 => '掃',
+ 194749 => '揤',
+ 194750 => '𢯱',
+ 194751 => '搢',
+ 194752 => '揅',
+ 194753 => '掩',
+ 194754 => '㨮',
+ 194755 => '摩',
+ 194756 => '摾',
+ 194757 => '撝',
+ 194758 => '摷',
+ 194759 => '㩬',
+ 194760 => '敏',
+ 194761 => '敬',
+ 194762 => '𣀊',
+ 194763 => '旣',
+ 194764 => '書',
+ 194765 => '晉',
+ 194766 => '㬙',
+ 194767 => '暑',
+ 194768 => '㬈',
+ 194769 => '㫤',
+ 194770 => '冒',
+ 194771 => '冕',
+ 194772 => '最',
+ 194773 => '暜',
+ 194774 => '肭',
+ 194775 => '䏙',
+ 194776 => '朗',
+ 194777 => '望',
+ 194778 => '朡',
+ 194779 => '杞',
+ 194780 => '杓',
+ 194781 => '𣏃',
+ 194782 => '㭉',
+ 194783 => '柺',
+ 194784 => '枅',
+ 194785 => '桒',
+ 194786 => '梅',
+ 194787 => '𣑭',
+ 194788 => '梎',
+ 194789 => '栟',
+ 194790 => '椔',
+ 194791 => '㮝',
+ 194792 => '楂',
+ 194793 => '榣',
+ 194794 => '槪',
+ 194795 => '檨',
+ 194796 => '𣚣',
+ 194797 => '櫛',
+ 194798 => '㰘',
+ 194799 => '次',
+ 194800 => '𣢧',
+ 194801 => '歔',
+ 194802 => '㱎',
+ 194803 => '歲',
+ 194804 => '殟',
+ 194805 => '殺',
+ 194806 => '殻',
+ 194807 => '𣪍',
+ 194808 => '𡴋',
+ 194809 => '𣫺',
+ 194810 => '汎',
+ 194811 => '𣲼',
+ 194812 => '沿',
+ 194813 => '泍',
+ 194814 => '汧',
+ 194815 => '洖',
+ 194816 => '派',
+ 194817 => '海',
+ 194818 => '流',
+ 194819 => '浩',
+ 194820 => '浸',
+ 194821 => '涅',
+ 194822 => '𣴞',
+ 194823 => '洴',
+ 194824 => '港',
+ 194825 => '湮',
+ 194826 => '㴳',
+ 194827 => '滋',
+ 194828 => '滇',
+ 194829 => '𣻑',
+ 194830 => '淹',
+ 194831 => '潮',
+ 194832 => '𣽞',
+ 194833 => '𣾎',
+ 194834 => '濆',
+ 194835 => '瀹',
+ 194836 => '瀞',
+ 194837 => '瀛',
+ 194838 => '㶖',
+ 194839 => '灊',
+ 194840 => '災',
+ 194841 => '灷',
+ 194842 => '炭',
+ 194843 => '𠔥',
+ 194844 => '煅',
+ 194845 => '𤉣',
+ 194846 => '熜',
+ 194848 => '爨',
+ 194849 => '爵',
+ 194850 => '牐',
+ 194851 => '𤘈',
+ 194852 => '犀',
+ 194853 => '犕',
+ 194854 => '𤜵',
+ 194855 => '𤠔',
+ 194856 => '獺',
+ 194857 => '王',
+ 194858 => '㺬',
+ 194859 => '玥',
+ 194860 => '㺸',
+ 194861 => '㺸',
+ 194862 => '瑇',
+ 194863 => '瑜',
+ 194864 => '瑱',
+ 194865 => '璅',
+ 194866 => '瓊',
+ 194867 => '㼛',
+ 194868 => '甤',
+ 194869 => '𤰶',
+ 194870 => '甾',
+ 194871 => '𤲒',
+ 194872 => '異',
+ 194873 => '𢆟',
+ 194874 => '瘐',
+ 194875 => '𤾡',
+ 194876 => '𤾸',
+ 194877 => '𥁄',
+ 194878 => '㿼',
+ 194879 => '䀈',
+ 194880 => '直',
+ 194881 => '𥃳',
+ 194882 => '𥃲',
+ 194883 => '𥄙',
+ 194884 => '𥄳',
+ 194885 => '眞',
+ 194886 => '真',
+ 194887 => '真',
+ 194888 => '睊',
+ 194889 => '䀹',
+ 194890 => '瞋',
+ 194891 => '䁆',
+ 194892 => '䂖',
+ 194893 => '𥐝',
+ 194894 => '硎',
+ 194895 => '碌',
+ 194896 => '磌',
+ 194897 => '䃣',
+ 194898 => '𥘦',
+ 194899 => '祖',
+ 194900 => '𥚚',
+ 194901 => '𥛅',
+ 194902 => '福',
+ 194903 => '秫',
+ 194904 => '䄯',
+ 194905 => '穀',
+ 194906 => '穊',
+ 194907 => '穏',
+ 194908 => '𥥼',
+ 194909 => '𥪧',
+ 194910 => '𥪧',
+ 194912 => '䈂',
+ 194913 => '𥮫',
+ 194914 => '篆',
+ 194915 => '築',
+ 194916 => '䈧',
+ 194917 => '𥲀',
+ 194918 => '糒',
+ 194919 => '䊠',
+ 194920 => '糨',
+ 194921 => '糣',
+ 194922 => '紀',
+ 194923 => '𥾆',
+ 194924 => '絣',
+ 194925 => '䌁',
+ 194926 => '緇',
+ 194927 => '縂',
+ 194928 => '繅',
+ 194929 => '䌴',
+ 194930 => '𦈨',
+ 194931 => '𦉇',
+ 194932 => '䍙',
+ 194933 => '𦋙',
+ 194934 => '罺',
+ 194935 => '𦌾',
+ 194936 => '羕',
+ 194937 => '翺',
+ 194938 => '者',
+ 194939 => '𦓚',
+ 194940 => '𦔣',
+ 194941 => '聠',
+ 194942 => '𦖨',
+ 194943 => '聰',
+ 194944 => '𣍟',
+ 194945 => '䏕',
+ 194946 => '育',
+ 194947 => '脃',
+ 194948 => '䐋',
+ 194949 => '脾',
+ 194950 => '媵',
+ 194951 => '𦞧',
+ 194952 => '𦞵',
+ 194953 => '𣎓',
+ 194954 => '𣎜',
+ 194955 => '舁',
+ 194956 => '舄',
+ 194957 => '辞',
+ 194958 => '䑫',
+ 194959 => '芑',
+ 194960 => '芋',
+ 194961 => '芝',
+ 194962 => '劳',
+ 194963 => '花',
+ 194964 => '芳',
+ 194965 => '芽',
+ 194966 => '苦',
+ 194967 => '𦬼',
+ 194968 => '若',
+ 194969 => '茝',
+ 194970 => '荣',
+ 194971 => '莭',
+ 194972 => '茣',
+ 194973 => '莽',
+ 194974 => '菧',
+ 194975 => '著',
+ 194976 => '荓',
+ 194977 => '菊',
+ 194978 => '菌',
+ 194979 => '菜',
+ 194980 => '𦰶',
+ 194981 => '𦵫',
+ 194982 => '𦳕',
+ 194983 => '䔫',
+ 194984 => '蓱',
+ 194985 => '蓳',
+ 194986 => '蔖',
+ 194987 => '𧏊',
+ 194988 => '蕤',
+ 194989 => '𦼬',
+ 194990 => '䕝',
+ 194991 => '䕡',
+ 194992 => '𦾱',
+ 194993 => '𧃒',
+ 194994 => '䕫',
+ 194995 => '虐',
+ 194996 => '虜',
+ 194997 => '虧',
+ 194998 => '虩',
+ 194999 => '蚩',
+ 195000 => '蚈',
+ 195001 => '蜎',
+ 195002 => '蛢',
+ 195003 => '蝹',
+ 195004 => '蜨',
+ 195005 => '蝫',
+ 195006 => '螆',
+ 195008 => '蟡',
+ 195009 => '蠁',
+ 195010 => '䗹',
+ 195011 => '衠',
+ 195012 => '衣',
+ 195013 => '𧙧',
+ 195014 => '裗',
+ 195015 => '裞',
+ 195016 => '䘵',
+ 195017 => '裺',
+ 195018 => '㒻',
+ 195019 => '𧢮',
+ 195020 => '𧥦',
+ 195021 => '䚾',
+ 195022 => '䛇',
+ 195023 => '誠',
+ 195024 => '諭',
+ 195025 => '變',
+ 195026 => '豕',
+ 195027 => '𧲨',
+ 195028 => '貫',
+ 195029 => '賁',
+ 195030 => '贛',
+ 195031 => '起',
+ 195032 => '𧼯',
+ 195033 => '𠠄',
+ 195034 => '跋',
+ 195035 => '趼',
+ 195036 => '跰',
+ 195037 => '𠣞',
+ 195038 => '軔',
+ 195039 => '輸',
+ 195040 => '𨗒',
+ 195041 => '𨗭',
+ 195042 => '邔',
+ 195043 => '郱',
+ 195044 => '鄑',
+ 195045 => '𨜮',
+ 195046 => '鄛',
+ 195047 => '鈸',
+ 195048 => '鋗',
+ 195049 => '鋘',
+ 195050 => '鉼',
+ 195051 => '鏹',
+ 195052 => '鐕',
+ 195053 => '𨯺',
+ 195054 => '開',
+ 195055 => '䦕',
+ 195056 => '閷',
+ 195057 => '𨵷',
+ 195058 => '䧦',
+ 195059 => '雃',
+ 195060 => '嶲',
+ 195061 => '霣',
+ 195062 => '𩅅',
+ 195063 => '𩈚',
+ 195064 => '䩮',
+ 195065 => '䩶',
+ 195066 => '韠',
+ 195067 => '𩐊',
+ 195068 => '䪲',
+ 195069 => '𩒖',
+ 195070 => '頋',
+ 195071 => '頋',
+ 195072 => '頩',
+ 195073 => '𩖶',
+ 195074 => '飢',
+ 195075 => '䬳',
+ 195076 => '餩',
+ 195077 => '馧',
+ 195078 => '駂',
+ 195079 => '駾',
+ 195080 => '䯎',
+ 195081 => '𩬰',
+ 195082 => '鬒',
+ 195083 => '鱀',
+ 195084 => '鳽',
+ 195085 => '䳎',
+ 195086 => '䳭',
+ 195087 => '鵧',
+ 195088 => '𪃎',
+ 195089 => '䳸',
+ 195090 => '𪄅',
+ 195091 => '𪈎',
+ 195092 => '𪊑',
+ 195093 => '麻',
+ 195094 => '䵖',
+ 195095 => '黹',
+ 195096 => '黾',
+ 195097 => '鼅',
+ 195098 => '鼏',
+ 195099 => '鼖',
+ 195100 => '鼻',
+ 195101 => '𪘀',
+);
diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php
new file mode 100644
index 0000000..1958e37
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php
@@ -0,0 +1,65 @@
+<?php
+
+return array (
+ 2381 => 9,
+ 2509 => 9,
+ 2637 => 9,
+ 2765 => 9,
+ 2893 => 9,
+ 3021 => 9,
+ 3149 => 9,
+ 3277 => 9,
+ 3387 => 9,
+ 3388 => 9,
+ 3405 => 9,
+ 3530 => 9,
+ 3642 => 9,
+ 3770 => 9,
+ 3972 => 9,
+ 4153 => 9,
+ 4154 => 9,
+ 5908 => 9,
+ 5940 => 9,
+ 6098 => 9,
+ 6752 => 9,
+ 6980 => 9,
+ 7082 => 9,
+ 7083 => 9,
+ 7154 => 9,
+ 7155 => 9,
+ 11647 => 9,
+ 43014 => 9,
+ 43052 => 9,
+ 43204 => 9,
+ 43347 => 9,
+ 43456 => 9,
+ 43766 => 9,
+ 44013 => 9,
+ 68159 => 9,
+ 69702 => 9,
+ 69759 => 9,
+ 69817 => 9,
+ 69939 => 9,
+ 69940 => 9,
+ 70080 => 9,
+ 70197 => 9,
+ 70378 => 9,
+ 70477 => 9,
+ 70722 => 9,
+ 70850 => 9,
+ 71103 => 9,
+ 71231 => 9,
+ 71350 => 9,
+ 71467 => 9,
+ 71737 => 9,
+ 71997 => 9,
+ 71998 => 9,
+ 72160 => 9,
+ 72244 => 9,
+ 72263 => 9,
+ 72345 => 9,
+ 72767 => 9,
+ 73028 => 9,
+ 73029 => 9,
+ 73111 => 9,
+);
diff --git a/vendor/symfony/polyfill-intl-idn/bootstrap.php b/vendor/symfony/polyfill-intl-idn/bootstrap.php
new file mode 100644
index 0000000..57c7835
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/bootstrap.php
@@ -0,0 +1,145 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Idn as p;
+
+if (extension_loaded('intl')) {
+ return;
+}
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!defined('U_IDNA_PROHIBITED_ERROR')) {
+ define('U_IDNA_PROHIBITED_ERROR', 66560);
+}
+if (!defined('U_IDNA_ERROR_START')) {
+ define('U_IDNA_ERROR_START', 66560);
+}
+if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
+ define('U_IDNA_UNASSIGNED_ERROR', 66561);
+}
+if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
+ define('U_IDNA_CHECK_BIDI_ERROR', 66562);
+}
+if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
+ define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
+}
+if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
+ define('U_IDNA_ACE_PREFIX_ERROR', 66564);
+}
+if (!defined('U_IDNA_VERIFICATION_ERROR')) {
+ define('U_IDNA_VERIFICATION_ERROR', 66565);
+}
+if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
+ define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
+}
+if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
+ define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
+}
+if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
+ define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
+}
+if (!defined('U_IDNA_ERROR_LIMIT')) {
+ define('U_IDNA_ERROR_LIMIT', 66569);
+}
+if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
+ define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
+}
+if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
+ define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
+}
+if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
+ define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
+}
+if (!defined('IDNA_DEFAULT')) {
+ define('IDNA_DEFAULT', 0);
+}
+if (!defined('IDNA_ALLOW_UNASSIGNED')) {
+ define('IDNA_ALLOW_UNASSIGNED', 1);
+}
+if (!defined('IDNA_USE_STD3_RULES')) {
+ define('IDNA_USE_STD3_RULES', 2);
+}
+if (!defined('IDNA_CHECK_BIDI')) {
+ define('IDNA_CHECK_BIDI', 4);
+}
+if (!defined('IDNA_CHECK_CONTEXTJ')) {
+ define('IDNA_CHECK_CONTEXTJ', 8);
+}
+if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
+ define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
+}
+if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
+ define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
+}
+if (!defined('INTL_IDNA_VARIANT_2003')) {
+ define('INTL_IDNA_VARIANT_2003', 0);
+}
+if (!defined('INTL_IDNA_VARIANT_UTS46')) {
+ define('INTL_IDNA_VARIANT_UTS46', 1);
+}
+if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
+ define('IDNA_ERROR_EMPTY_LABEL', 1);
+}
+if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
+ define('IDNA_ERROR_LABEL_TOO_LONG', 2);
+}
+if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
+ define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
+}
+if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
+ define('IDNA_ERROR_LEADING_HYPHEN', 8);
+}
+if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
+ define('IDNA_ERROR_TRAILING_HYPHEN', 16);
+}
+if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
+ define('IDNA_ERROR_HYPHEN_3_4', 32);
+}
+if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
+ define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
+}
+if (!defined('IDNA_ERROR_DISALLOWED')) {
+ define('IDNA_ERROR_DISALLOWED', 128);
+}
+if (!defined('IDNA_ERROR_PUNYCODE')) {
+ define('IDNA_ERROR_PUNYCODE', 256);
+}
+if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
+ define('IDNA_ERROR_LABEL_HAS_DOT', 512);
+}
+if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
+ define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
+}
+if (!defined('IDNA_ERROR_BIDI')) {
+ define('IDNA_ERROR_BIDI', 2048);
+}
+if (!defined('IDNA_ERROR_CONTEXTJ')) {
+ define('IDNA_ERROR_CONTEXTJ', 4096);
+}
+
+if (\PHP_VERSION_ID < 70400) {
+ if (!function_exists('idn_to_ascii')) {
+ function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
+ }
+ if (!function_exists('idn_to_utf8')) {
+ function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
+ }
+} else {
+ if (!function_exists('idn_to_ascii')) {
+ function idn_to_ascii($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }
+ }
+ if (!function_exists('idn_to_utf8')) {
+ function idn_to_utf8($domain, $flags = 0, $variant = \INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/bootstrap80.php b/vendor/symfony/polyfill-intl-idn/bootstrap80.php
new file mode 100644
index 0000000..a62c2d6
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/bootstrap80.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Idn as p;
+
+if (!defined('U_IDNA_PROHIBITED_ERROR')) {
+ define('U_IDNA_PROHIBITED_ERROR', 66560);
+}
+if (!defined('U_IDNA_ERROR_START')) {
+ define('U_IDNA_ERROR_START', 66560);
+}
+if (!defined('U_IDNA_UNASSIGNED_ERROR')) {
+ define('U_IDNA_UNASSIGNED_ERROR', 66561);
+}
+if (!defined('U_IDNA_CHECK_BIDI_ERROR')) {
+ define('U_IDNA_CHECK_BIDI_ERROR', 66562);
+}
+if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {
+ define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);
+}
+if (!defined('U_IDNA_ACE_PREFIX_ERROR')) {
+ define('U_IDNA_ACE_PREFIX_ERROR', 66564);
+}
+if (!defined('U_IDNA_VERIFICATION_ERROR')) {
+ define('U_IDNA_VERIFICATION_ERROR', 66565);
+}
+if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {
+ define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);
+}
+if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {
+ define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);
+}
+if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {
+ define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);
+}
+if (!defined('U_IDNA_ERROR_LIMIT')) {
+ define('U_IDNA_ERROR_LIMIT', 66569);
+}
+if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {
+ define('U_STRINGPREP_PROHIBITED_ERROR', 66560);
+}
+if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {
+ define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);
+}
+if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {
+ define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);
+}
+if (!defined('IDNA_DEFAULT')) {
+ define('IDNA_DEFAULT', 0);
+}
+if (!defined('IDNA_ALLOW_UNASSIGNED')) {
+ define('IDNA_ALLOW_UNASSIGNED', 1);
+}
+if (!defined('IDNA_USE_STD3_RULES')) {
+ define('IDNA_USE_STD3_RULES', 2);
+}
+if (!defined('IDNA_CHECK_BIDI')) {
+ define('IDNA_CHECK_BIDI', 4);
+}
+if (!defined('IDNA_CHECK_CONTEXTJ')) {
+ define('IDNA_CHECK_CONTEXTJ', 8);
+}
+if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {
+ define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);
+}
+if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
+ define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);
+}
+if (!defined('INTL_IDNA_VARIANT_UTS46')) {
+ define('INTL_IDNA_VARIANT_UTS46', 1);
+}
+if (!defined('IDNA_ERROR_EMPTY_LABEL')) {
+ define('IDNA_ERROR_EMPTY_LABEL', 1);
+}
+if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {
+ define('IDNA_ERROR_LABEL_TOO_LONG', 2);
+}
+if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {
+ define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);
+}
+if (!defined('IDNA_ERROR_LEADING_HYPHEN')) {
+ define('IDNA_ERROR_LEADING_HYPHEN', 8);
+}
+if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {
+ define('IDNA_ERROR_TRAILING_HYPHEN', 16);
+}
+if (!defined('IDNA_ERROR_HYPHEN_3_4')) {
+ define('IDNA_ERROR_HYPHEN_3_4', 32);
+}
+if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {
+ define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);
+}
+if (!defined('IDNA_ERROR_DISALLOWED')) {
+ define('IDNA_ERROR_DISALLOWED', 128);
+}
+if (!defined('IDNA_ERROR_PUNYCODE')) {
+ define('IDNA_ERROR_PUNYCODE', 256);
+}
+if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {
+ define('IDNA_ERROR_LABEL_HAS_DOT', 512);
+}
+if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {
+ define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);
+}
+if (!defined('IDNA_ERROR_BIDI')) {
+ define('IDNA_ERROR_BIDI', 2048);
+}
+if (!defined('IDNA_ERROR_CONTEXTJ')) {
+ define('IDNA_ERROR_CONTEXTJ', 4096);
+}
+
+if (!function_exists('idn_to_ascii')) {
+ function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); }
+}
+if (!function_exists('idn_to_utf8')) {
+ function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); }
+}
diff --git a/vendor/symfony/polyfill-intl-idn/composer.json b/vendor/symfony/polyfill-intl-idn/composer.json
new file mode 100644
index 0000000..71030a2
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-idn/composer.json
@@ -0,0 +1,44 @@
+{
+ "name": "symfony/polyfill-intl-idn",
+ "type": "library",
+ "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "idn"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Laurent Bassin",
+ "email": "laurent@bassin.info"
+ },
+ {
+ "name": "Trevor Rowbotham",
+ "email": "trevor.rowbotham@pm.me"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1",
+ "symfony/polyfill-intl-normalizer": "^1.10",
+ "symfony/polyfill-php72": "^1.10"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" },
+ "files": [ "bootstrap.php" ]
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/LICENSE b/vendor/symfony/polyfill-intl-normalizer/LICENSE
new file mode 100644
index 0000000..4cd8bdd
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-2019 Fabien Potencier
+
+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/symfony/polyfill-intl-normalizer/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
new file mode 100644
index 0000000..4443c23
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
@@ -0,0 +1,310 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Intl\Normalizer;
+
+/**
+ * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.
+ *
+ * It has been validated with Unicode 6.3 Normalization Conformance Test.
+ * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.
+ *
+ * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @internal
+ */
+class Normalizer
+{
+ public const FORM_D = \Normalizer::FORM_D;
+ public const FORM_KD = \Normalizer::FORM_KD;
+ public const FORM_C = \Normalizer::FORM_C;
+ public const FORM_KC = \Normalizer::FORM_KC;
+ public const NFD = \Normalizer::NFD;
+ public const NFKD = \Normalizer::NFKD;
+ public const NFC = \Normalizer::NFC;
+ public const NFKC = \Normalizer::NFKC;
+
+ private static $C;
+ private static $D;
+ private static $KD;
+ private static $cC;
+ private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
+ private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
+
+ public static function isNormalized(string $s, int $form = self::FORM_C)
+ {
+ if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {
+ return false;
+ }
+ if (!isset($s[strspn($s, self::$ASCII)])) {
+ return true;
+ }
+ if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) {
+ return true;
+ }
+
+ return self::normalize($s, $form) === $s;
+ }
+
+ public static function normalize(string $s, int $form = self::FORM_C)
+ {
+ if (!preg_match('//u', $s)) {
+ return false;
+ }
+
+ switch ($form) {
+ case self::NFC: $C = true; $K = false; break;
+ case self::NFD: $C = false; $K = false; break;
+ case self::NFKC: $C = true; $K = true; break;
+ case self::NFKD: $C = false; $K = true; break;
+ default:
+ if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) {
+ return $s;
+ }
+
+ if (80000 > \PHP_VERSION_ID) {
+ return false;
+ }
+
+ throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');
+ }
+
+ if ('' === $s) {
+ return '';
+ }
+
+ if ($K && null === self::$KD) {
+ self::$KD = self::getData('compatibilityDecomposition');
+ }
+
+ if (null === self::$D) {
+ self::$D = self::getData('canonicalDecomposition');
+ self::$cC = self::getData('combiningClass');
+ }
+
+ if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {
+ mb_internal_encoding('8bit');
+ }
+
+ $r = self::decompose($s, $K);
+
+ if ($C) {
+ if (null === self::$C) {
+ self::$C = self::getData('canonicalComposition');
+ }
+
+ $r = self::recompose($r);
+ }
+ if (null !== $mbEncoding) {
+ mb_internal_encoding($mbEncoding);
+ }
+
+ return $r;
+ }
+
+ private static function recompose($s)
+ {
+ $ASCII = self::$ASCII;
+ $compMap = self::$C;
+ $combClass = self::$cC;
+ $ulenMask = self::$ulenMask;
+
+ $result = $tail = '';
+
+ $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"];
+ $len = \strlen($s);
+
+ $lastUchr = substr($s, 0, $i);
+ $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;
+
+ while ($i < $len) {
+ if ($s[$i] < "\x80") {
+ // ASCII chars
+
+ if ($tail) {
+ $lastUchr .= $tail;
+ $tail = '';
+ }
+
+ if ($j = strspn($s, $ASCII, $i + 1)) {
+ $lastUchr .= substr($s, $i, $j);
+ $i += $j;
+ }
+
+ $result .= $lastUchr;
+ $lastUchr = $s[$i];
+ $lastUcls = 0;
+ ++$i;
+ continue;
+ }
+
+ $ulen = $ulenMask[$s[$i] & "\xF0"];
+ $uchr = substr($s, $i, $ulen);
+
+ if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr
+ || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
+ || $lastUcls) {
+ // Table lookup and combining chars composition
+
+ $ucls = $combClass[$uchr] ?? 0;
+
+ if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {
+ $lastUchr = $compMap[$lastUchr.$uchr];
+ } elseif ($lastUcls = $ucls) {
+ $tail .= $uchr;
+ } else {
+ if ($tail) {
+ $lastUchr .= $tail;
+ $tail = '';
+ }
+
+ $result .= $lastUchr;
+ $lastUchr = $uchr;
+ }
+ } else {
+ // Hangul chars
+
+ $L = \ord($lastUchr[2]) - 0x80;
+ $V = \ord($uchr[2]) - 0xA1;
+ $T = 0;
+
+ $uchr = substr($s, $i + $ulen, 3);
+
+ if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") {
+ $T = \ord($uchr[2]) - 0xA7;
+ 0 > $T && $T += 0x40;
+ $ulen += 3;
+ }
+
+ $L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
+ $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F);
+ }
+
+ $i += $ulen;
+ }
+
+ return $result.$lastUchr.$tail;
+ }
+
+ private static function decompose($s, $c)
+ {
+ $result = '';
+
+ $ASCII = self::$ASCII;
+ $decompMap = self::$D;
+ $combClass = self::$cC;
+ $ulenMask = self::$ulenMask;
+ if ($c) {
+ $compatMap = self::$KD;
+ }
+
+ $c = [];
+ $i = 0;
+ $len = \strlen($s);
+
+ while ($i < $len) {
+ if ($s[$i] < "\x80") {
+ // ASCII chars
+
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ $c = [];
+ }
+
+ $j = 1 + strspn($s, $ASCII, $i + 1);
+ $result .= substr($s, $i, $j);
+ $i += $j;
+ continue;
+ }
+
+ $ulen = $ulenMask[$s[$i] & "\xF0"];
+ $uchr = substr($s, $i, $ulen);
+ $i += $ulen;
+
+ if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {
+ // Table lookup
+
+ if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {
+ $uchr = $j;
+
+ $j = \strlen($uchr);
+ $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"];
+
+ if ($ulen != $j) {
+ // Put trailing chars in $s
+
+ $j -= $ulen;
+ $i -= $j;
+
+ if (0 > $i) {
+ $s = str_repeat(' ', -$i).$s;
+ $len -= $i;
+ $i = 0;
+ }
+
+ while ($j--) {
+ $s[$i + $j] = $uchr[$ulen + $j];
+ }
+
+ $uchr = substr($uchr, 0, $ulen);
+ }
+ }
+ if (isset($combClass[$uchr])) {
+ // Combining chars, for sorting
+
+ if (!isset($c[$combClass[$uchr]])) {
+ $c[$combClass[$uchr]] = '';
+ }
+ $c[$combClass[$uchr]] .= $uchr;
+ continue;
+ }
+ } else {
+ // Hangul chars
+
+ $uchr = unpack('C*', $uchr);
+ $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;
+
+ $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588))
+ ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28));
+
+ if ($j %= 28) {
+ $uchr .= $j < 25
+ ? ("\xE1\x86".\chr(0xA7 + $j))
+ : ("\xE1\x87".\chr(0x67 + $j));
+ }
+ }
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ $c = [];
+ }
+
+ $result .= $uchr;
+ }
+
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ }
+
+ return $result;
+ }
+
+ private static function getData($file)
+ {
+ if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
+ return require $file;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php
new file mode 100644
index 0000000..0fdfc89
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php
@@ -0,0 +1,17 @@
+<?php
+
+class Normalizer extends Symfony\Polyfill\Intl\Normalizer\Normalizer
+{
+ /**
+ * @deprecated since ICU 56 and removed in PHP 8
+ */
+ public const NONE = 2;
+ public const FORM_D = 4;
+ public const FORM_KD = 8;
+ public const FORM_C = 16;
+ public const FORM_KC = 32;
+ public const NFD = 4;
+ public const NFKD = 8;
+ public const NFC = 16;
+ public const NFKC = 32;
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php
new file mode 100644
index 0000000..db47644
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php
@@ -0,0 +1,945 @@
+<?php
+
+return array (
+ 'À' => 'À',
+ 'Á' => 'Á',
+ 'Â' => 'Â',
+ 'Ã' => 'Ã',
+ 'Ä' => 'Ä',
+ 'Å' => 'Å',
+ 'Ç' => 'Ç',
+ 'È' => 'È',
+ 'É' => 'É',
+ 'Ê' => 'Ê',
+ 'Ë' => 'Ë',
+ 'Ì' => 'Ì',
+ 'Í' => 'Í',
+ 'Î' => 'Î',
+ 'Ï' => 'Ï',
+ 'Ñ' => 'Ñ',
+ 'Ò' => 'Ò',
+ 'Ó' => 'Ó',
+ 'Ô' => 'Ô',
+ 'Õ' => 'Õ',
+ 'Ö' => 'Ö',
+ 'Ù' => 'Ù',
+ 'Ú' => 'Ú',
+ 'Û' => 'Û',
+ 'Ü' => 'Ü',
+ 'Ý' => 'Ý',
+ 'à' => 'à',
+ 'á' => 'á',
+ 'â' => 'â',
+ 'ã' => 'ã',
+ 'ä' => 'ä',
+ 'å' => 'å',
+ 'ç' => 'ç',
+ 'è' => 'è',
+ 'é' => 'é',
+ 'ê' => 'ê',
+ 'ë' => 'ë',
+ 'ì' => 'ì',
+ 'í' => 'í',
+ 'î' => 'î',
+ 'ï' => 'ï',
+ 'ñ' => 'ñ',
+ 'ò' => 'ò',
+ 'ó' => 'ó',
+ 'ô' => 'ô',
+ 'õ' => 'õ',
+ 'ö' => 'ö',
+ 'ù' => 'ù',
+ 'ú' => 'ú',
+ 'û' => 'û',
+ 'ü' => 'ü',
+ 'ý' => 'ý',
+ 'ÿ' => 'ÿ',
+ 'Ā' => 'Ā',
+ 'ā' => 'ā',
+ 'Ă' => 'Ă',
+ 'ă' => 'ă',
+ 'Ą' => 'Ą',
+ 'ą' => 'ą',
+ 'Ć' => 'Ć',
+ 'ć' => 'ć',
+ 'Ĉ' => 'Ĉ',
+ 'ĉ' => 'ĉ',
+ 'Ċ' => 'Ċ',
+ 'ċ' => 'ċ',
+ 'Č' => 'Č',
+ 'č' => 'č',
+ 'Ď' => 'Ď',
+ 'ď' => 'ď',
+ 'Ē' => 'Ē',
+ 'ē' => 'ē',
+ 'Ĕ' => 'Ĕ',
+ 'ĕ' => 'ĕ',
+ 'Ė' => 'Ė',
+ 'ė' => 'ė',
+ 'Ę' => 'Ę',
+ 'ę' => 'ę',
+ 'Ě' => 'Ě',
+ 'ě' => 'ě',
+ 'Ĝ' => 'Ĝ',
+ 'ĝ' => 'ĝ',
+ 'Ğ' => 'Ğ',
+ 'ğ' => 'ğ',
+ 'Ġ' => 'Ġ',
+ 'ġ' => 'ġ',
+ 'Ģ' => 'Ģ',
+ 'ģ' => 'ģ',
+ 'Ĥ' => 'Ĥ',
+ 'ĥ' => 'ĥ',
+ 'Ĩ' => 'Ĩ',
+ 'ĩ' => 'ĩ',
+ 'Ī' => 'Ī',
+ 'ī' => 'ī',
+ 'Ĭ' => 'Ĭ',
+ 'ĭ' => 'ĭ',
+ 'Į' => 'Į',
+ 'į' => 'į',
+ 'İ' => 'İ',
+ 'Ĵ' => 'Ĵ',
+ 'ĵ' => 'ĵ',
+ 'Ķ' => 'Ķ',
+ 'ķ' => 'ķ',
+ 'Ĺ' => 'Ĺ',
+ 'ĺ' => 'ĺ',
+ 'Ļ' => 'Ļ',
+ 'ļ' => 'ļ',
+ 'Ľ' => 'Ľ',
+ 'ľ' => 'ľ',
+ 'Ń' => 'Ń',
+ 'ń' => 'ń',
+ 'Ņ' => 'Ņ',
+ 'ņ' => 'ņ',
+ 'Ň' => 'Ň',
+ 'ň' => 'ň',
+ 'Ō' => 'Ō',
+ 'ō' => 'ō',
+ 'Ŏ' => 'Ŏ',
+ 'ŏ' => 'ŏ',
+ 'Ő' => 'Ő',
+ 'ő' => 'ő',
+ 'Ŕ' => 'Ŕ',
+ 'ŕ' => 'ŕ',
+ 'Ŗ' => 'Ŗ',
+ 'ŗ' => 'ŗ',
+ 'Ř' => 'Ř',
+ 'ř' => 'ř',
+ 'Ś' => 'Ś',
+ 'ś' => 'ś',
+ 'Ŝ' => 'Ŝ',
+ 'ŝ' => 'ŝ',
+ 'Ş' => 'Ş',
+ 'ş' => 'ş',
+ 'Š' => 'Š',
+ 'š' => 'š',
+ 'Ţ' => 'Ţ',
+ 'ţ' => 'ţ',
+ 'Ť' => 'Ť',
+ 'ť' => 'ť',
+ 'Ũ' => 'Ũ',
+ 'ũ' => 'ũ',
+ 'Ū' => 'Ū',
+ 'ū' => 'ū',
+ 'Ŭ' => 'Ŭ',
+ 'ŭ' => 'ŭ',
+ 'Ů' => 'Ů',
+ 'ů' => 'ů',
+ 'Ű' => 'Ű',
+ 'ű' => 'ű',
+ 'Ų' => 'Ų',
+ 'ų' => 'ų',
+ 'Ŵ' => 'Ŵ',
+ 'ŵ' => 'ŵ',
+ 'Ŷ' => 'Ŷ',
+ 'ŷ' => 'ŷ',
+ 'Ÿ' => 'Ÿ',
+ 'Ź' => 'Ź',
+ 'ź' => 'ź',
+ 'Ż' => 'Ż',
+ 'ż' => 'ż',
+ 'Ž' => 'Ž',
+ 'ž' => 'ž',
+ 'Ơ' => 'Ơ',
+ 'ơ' => 'ơ',
+ 'Ư' => 'Ư',
+ 'ư' => 'ư',
+ 'Ǎ' => 'Ǎ',
+ 'ǎ' => 'ǎ',
+ 'Ǐ' => 'Ǐ',
+ 'ǐ' => 'ǐ',
+ 'Ǒ' => 'Ǒ',
+ 'ǒ' => 'ǒ',
+ 'Ǔ' => 'Ǔ',
+ 'ǔ' => 'ǔ',
+ 'Ǖ' => 'Ǖ',
+ 'ǖ' => 'ǖ',
+ 'Ǘ' => 'Ǘ',
+ 'ǘ' => 'ǘ',
+ 'Ǚ' => 'Ǚ',
+ 'ǚ' => 'ǚ',
+ 'Ǜ' => 'Ǜ',
+ 'ǜ' => 'ǜ',
+ 'Ǟ' => 'Ǟ',
+ 'ǟ' => 'ǟ',
+ 'Ǡ' => 'Ǡ',
+ 'ǡ' => 'ǡ',
+ 'Ǣ' => 'Ǣ',
+ 'ǣ' => 'ǣ',
+ 'Ǧ' => 'Ǧ',
+ 'ǧ' => 'ǧ',
+ 'Ǩ' => 'Ǩ',
+ 'ǩ' => 'ǩ',
+ 'Ǫ' => 'Ǫ',
+ 'ǫ' => 'ǫ',
+ 'Ǭ' => 'Ǭ',
+ 'ǭ' => 'ǭ',
+ 'Ǯ' => 'Ǯ',
+ 'ǯ' => 'ǯ',
+ 'ǰ' => 'ǰ',
+ 'Ǵ' => 'Ǵ',
+ 'ǵ' => 'ǵ',
+ 'Ǹ' => 'Ǹ',
+ 'ǹ' => 'ǹ',
+ 'Ǻ' => 'Ǻ',
+ 'ǻ' => 'ǻ',
+ 'Ǽ' => 'Ǽ',
+ 'ǽ' => 'ǽ',
+ 'Ǿ' => 'Ǿ',
+ 'ǿ' => 'ǿ',
+ 'Ȁ' => 'Ȁ',
+ 'ȁ' => 'ȁ',
+ 'Ȃ' => 'Ȃ',
+ 'ȃ' => 'ȃ',
+ 'Ȅ' => 'Ȅ',
+ 'ȅ' => 'ȅ',
+ 'Ȇ' => 'Ȇ',
+ 'ȇ' => 'ȇ',
+ 'Ȉ' => 'Ȉ',
+ 'ȉ' => 'ȉ',
+ 'Ȋ' => 'Ȋ',
+ 'ȋ' => 'ȋ',
+ 'Ȍ' => 'Ȍ',
+ 'ȍ' => 'ȍ',
+ 'Ȏ' => 'Ȏ',
+ 'ȏ' => 'ȏ',
+ 'Ȑ' => 'Ȑ',
+ 'ȑ' => 'ȑ',
+ 'Ȓ' => 'Ȓ',
+ 'ȓ' => 'ȓ',
+ 'Ȕ' => 'Ȕ',
+ 'ȕ' => 'ȕ',
+ 'Ȗ' => 'Ȗ',
+ 'ȗ' => 'ȗ',
+ 'Ș' => 'Ș',
+ 'ș' => 'ș',
+ 'Ț' => 'Ț',
+ 'ț' => 'ț',
+ 'Ȟ' => 'Ȟ',
+ 'ȟ' => 'ȟ',
+ 'Ȧ' => 'Ȧ',
+ 'ȧ' => 'ȧ',
+ 'Ȩ' => 'Ȩ',
+ 'ȩ' => 'ȩ',
+ 'Ȫ' => 'Ȫ',
+ 'ȫ' => 'ȫ',
+ 'Ȭ' => 'Ȭ',
+ 'ȭ' => 'ȭ',
+ 'Ȯ' => 'Ȯ',
+ 'ȯ' => 'ȯ',
+ 'Ȱ' => 'Ȱ',
+ 'ȱ' => 'ȱ',
+ 'Ȳ' => 'Ȳ',
+ 'ȳ' => 'ȳ',
+ '΅' => '΅',
+ 'Ά' => 'Ά',
+ 'Έ' => 'Έ',
+ 'Ή' => 'Ή',
+ 'Ί' => 'Ί',
+ 'Ό' => 'Ό',
+ 'Ύ' => 'Ύ',
+ 'Ώ' => 'Ώ',
+ 'ΐ' => 'ΐ',
+ 'Ϊ' => 'Ϊ',
+ 'Ϋ' => 'Ϋ',
+ 'ά' => 'ά',
+ 'έ' => 'έ',
+ 'ή' => 'ή',
+ 'ί' => 'ί',
+ 'ΰ' => 'ΰ',
+ 'ϊ' => 'ϊ',
+ 'ϋ' => 'ϋ',
+ 'ό' => 'ό',
+ 'ύ' => 'ύ',
+ 'ώ' => 'ώ',
+ 'ϓ' => 'ϓ',
+ 'ϔ' => 'ϔ',
+ 'Ѐ' => 'Ѐ',
+ 'Ё' => 'Ё',
+ 'Ѓ' => 'Ѓ',
+ 'Ї' => 'Ї',
+ 'Ќ' => 'Ќ',
+ 'Ѝ' => 'Ѝ',
+ 'Ў' => 'Ў',
+ 'Й' => 'Й',
+ 'й' => 'й',
+ 'ѐ' => 'ѐ',
+ 'ё' => 'ё',
+ 'ѓ' => 'ѓ',
+ 'ї' => 'ї',
+ 'ќ' => 'ќ',
+ 'ѝ' => 'ѝ',
+ 'ў' => 'ў',
+ 'Ѷ' => 'Ѷ',
+ 'ѷ' => 'ѷ',
+ 'Ӂ' => 'Ӂ',
+ 'ӂ' => 'ӂ',
+ 'Ӑ' => 'Ӑ',
+ 'ӑ' => 'ӑ',
+ 'Ӓ' => 'Ӓ',
+ 'ӓ' => 'ӓ',
+ 'Ӗ' => 'Ӗ',
+ 'ӗ' => 'ӗ',
+ 'Ӛ' => 'Ӛ',
+ 'ӛ' => 'ӛ',
+ 'Ӝ' => 'Ӝ',
+ 'ӝ' => 'ӝ',
+ 'Ӟ' => 'Ӟ',
+ 'ӟ' => 'ӟ',
+ 'Ӣ' => 'Ӣ',
+ 'ӣ' => 'ӣ',
+ 'Ӥ' => 'Ӥ',
+ 'ӥ' => 'ӥ',
+ 'Ӧ' => 'Ӧ',
+ 'ӧ' => 'ӧ',
+ 'Ӫ' => 'Ӫ',
+ 'ӫ' => 'ӫ',
+ 'Ӭ' => 'Ӭ',
+ 'ӭ' => 'ӭ',
+ 'Ӯ' => 'Ӯ',
+ 'ӯ' => 'ӯ',
+ 'Ӱ' => 'Ӱ',
+ 'ӱ' => 'ӱ',
+ 'Ӳ' => 'Ӳ',
+ 'ӳ' => 'ӳ',
+ 'Ӵ' => 'Ӵ',
+ 'ӵ' => 'ӵ',
+ 'Ӹ' => 'Ӹ',
+ 'ӹ' => 'ӹ',
+ 'آ' => 'آ',
+ 'أ' => 'أ',
+ 'ؤ' => 'ؤ',
+ 'إ' => 'إ',
+ 'ئ' => 'ئ',
+ 'ۀ' => 'ۀ',
+ 'ۂ' => 'ۂ',
+ 'ۓ' => 'ۓ',
+ 'ऩ' => 'ऩ',
+ 'ऱ' => 'ऱ',
+ 'ऴ' => 'ऴ',
+ 'ো' => 'ো',
+ 'ৌ' => 'ৌ',
+ 'ୈ' => 'ୈ',
+ 'ୋ' => 'ୋ',
+ 'ୌ' => 'ୌ',
+ 'ஔ' => 'ஔ',
+ 'ொ' => 'ொ',
+ 'ோ' => 'ோ',
+ 'ௌ' => 'ௌ',
+ 'ై' => 'ై',
+ 'ೀ' => 'ೀ',
+ 'ೇ' => 'ೇ',
+ 'ೈ' => 'ೈ',
+ 'ೊ' => 'ೊ',
+ 'ೋ' => 'ೋ',
+ 'ൊ' => 'ൊ',
+ 'ോ' => 'ോ',
+ 'ൌ' => 'ൌ',
+ 'ේ' => 'ේ',
+ 'ො' => 'ො',
+ 'ෝ' => 'ෝ',
+ 'ෞ' => 'ෞ',
+ 'ဦ' => 'ဦ',
+ 'ᬆ' => 'ᬆ',
+ 'ᬈ' => 'ᬈ',
+ 'ᬊ' => 'ᬊ',
+ 'ᬌ' => 'ᬌ',
+ 'ᬎ' => 'ᬎ',
+ 'ᬒ' => 'ᬒ',
+ 'ᬻ' => 'ᬻ',
+ 'ᬽ' => 'ᬽ',
+ 'ᭀ' => 'ᭀ',
+ 'ᭁ' => 'ᭁ',
+ 'ᭃ' => 'ᭃ',
+ 'Ḁ' => 'Ḁ',
+ 'ḁ' => 'ḁ',
+ 'Ḃ' => 'Ḃ',
+ 'ḃ' => 'ḃ',
+ 'Ḅ' => 'Ḅ',
+ 'ḅ' => 'ḅ',
+ 'Ḇ' => 'Ḇ',
+ 'ḇ' => 'ḇ',
+ 'Ḉ' => 'Ḉ',
+ 'ḉ' => 'ḉ',
+ 'Ḋ' => 'Ḋ',
+ 'ḋ' => 'ḋ',
+ 'Ḍ' => 'Ḍ',
+ 'ḍ' => 'ḍ',
+ 'Ḏ' => 'Ḏ',
+ 'ḏ' => 'ḏ',
+ 'Ḑ' => 'Ḑ',
+ 'ḑ' => 'ḑ',
+ 'Ḓ' => 'Ḓ',
+ 'ḓ' => 'ḓ',
+ 'Ḕ' => 'Ḕ',
+ 'ḕ' => 'ḕ',
+ 'Ḗ' => 'Ḗ',
+ 'ḗ' => 'ḗ',
+ 'Ḙ' => 'Ḙ',
+ 'ḙ' => 'ḙ',
+ 'Ḛ' => 'Ḛ',
+ 'ḛ' => 'ḛ',
+ 'Ḝ' => 'Ḝ',
+ 'ḝ' => 'ḝ',
+ 'Ḟ' => 'Ḟ',
+ 'ḟ' => 'ḟ',
+ 'Ḡ' => 'Ḡ',
+ 'ḡ' => 'ḡ',
+ 'Ḣ' => 'Ḣ',
+ 'ḣ' => 'ḣ',
+ 'Ḥ' => 'Ḥ',
+ 'ḥ' => 'ḥ',
+ 'Ḧ' => 'Ḧ',
+ 'ḧ' => 'ḧ',
+ 'Ḩ' => 'Ḩ',
+ 'ḩ' => 'ḩ',
+ 'Ḫ' => 'Ḫ',
+ 'ḫ' => 'ḫ',
+ 'Ḭ' => 'Ḭ',
+ 'ḭ' => 'ḭ',
+ 'Ḯ' => 'Ḯ',
+ 'ḯ' => 'ḯ',
+ 'Ḱ' => 'Ḱ',
+ 'ḱ' => 'ḱ',
+ 'Ḳ' => 'Ḳ',
+ 'ḳ' => 'ḳ',
+ 'Ḵ' => 'Ḵ',
+ 'ḵ' => 'ḵ',
+ 'Ḷ' => 'Ḷ',
+ 'ḷ' => 'ḷ',
+ 'Ḹ' => 'Ḹ',
+ 'ḹ' => 'ḹ',
+ 'Ḻ' => 'Ḻ',
+ 'ḻ' => 'ḻ',
+ 'Ḽ' => 'Ḽ',
+ 'ḽ' => 'ḽ',
+ 'Ḿ' => 'Ḿ',
+ 'ḿ' => 'ḿ',
+ 'Ṁ' => 'Ṁ',
+ 'ṁ' => 'ṁ',
+ 'Ṃ' => 'Ṃ',
+ 'ṃ' => 'ṃ',
+ 'Ṅ' => 'Ṅ',
+ 'ṅ' => 'ṅ',
+ 'Ṇ' => 'Ṇ',
+ 'ṇ' => 'ṇ',
+ 'Ṉ' => 'Ṉ',
+ 'ṉ' => 'ṉ',
+ 'Ṋ' => 'Ṋ',
+ 'ṋ' => 'ṋ',
+ 'Ṍ' => 'Ṍ',
+ 'ṍ' => 'ṍ',
+ 'Ṏ' => 'Ṏ',
+ 'ṏ' => 'ṏ',
+ 'Ṑ' => 'Ṑ',
+ 'ṑ' => 'ṑ',
+ 'Ṓ' => 'Ṓ',
+ 'ṓ' => 'ṓ',
+ 'Ṕ' => 'Ṕ',
+ 'ṕ' => 'ṕ',
+ 'Ṗ' => 'Ṗ',
+ 'ṗ' => 'ṗ',
+ 'Ṙ' => 'Ṙ',
+ 'ṙ' => 'ṙ',
+ 'Ṛ' => 'Ṛ',
+ 'ṛ' => 'ṛ',
+ 'Ṝ' => 'Ṝ',
+ 'ṝ' => 'ṝ',
+ 'Ṟ' => 'Ṟ',
+ 'ṟ' => 'ṟ',
+ 'Ṡ' => 'Ṡ',
+ 'ṡ' => 'ṡ',
+ 'Ṣ' => 'Ṣ',
+ 'ṣ' => 'ṣ',
+ 'Ṥ' => 'Ṥ',
+ 'ṥ' => 'ṥ',
+ 'Ṧ' => 'Ṧ',
+ 'ṧ' => 'ṧ',
+ 'Ṩ' => 'Ṩ',
+ 'ṩ' => 'ṩ',
+ 'Ṫ' => 'Ṫ',
+ 'ṫ' => 'ṫ',
+ 'Ṭ' => 'Ṭ',
+ 'ṭ' => 'ṭ',
+ 'Ṯ' => 'Ṯ',
+ 'ṯ' => 'ṯ',
+ 'Ṱ' => 'Ṱ',
+ 'ṱ' => 'ṱ',
+ 'Ṳ' => 'Ṳ',
+ 'ṳ' => 'ṳ',
+ 'Ṵ' => 'Ṵ',
+ 'ṵ' => 'ṵ',
+ 'Ṷ' => 'Ṷ',
+ 'ṷ' => 'ṷ',
+ 'Ṹ' => 'Ṹ',
+ 'ṹ' => 'ṹ',
+ 'Ṻ' => 'Ṻ',
+ 'ṻ' => 'ṻ',
+ 'Ṽ' => 'Ṽ',
+ 'ṽ' => 'ṽ',
+ 'Ṿ' => 'Ṿ',
+ 'ṿ' => 'ṿ',
+ 'Ẁ' => 'Ẁ',
+ 'ẁ' => 'ẁ',
+ 'Ẃ' => 'Ẃ',
+ 'ẃ' => 'ẃ',
+ 'Ẅ' => 'Ẅ',
+ 'ẅ' => 'ẅ',
+ 'Ẇ' => 'Ẇ',
+ 'ẇ' => 'ẇ',
+ 'Ẉ' => 'Ẉ',
+ 'ẉ' => 'ẉ',
+ 'Ẋ' => 'Ẋ',
+ 'ẋ' => 'ẋ',
+ 'Ẍ' => 'Ẍ',
+ 'ẍ' => 'ẍ',
+ 'Ẏ' => 'Ẏ',
+ 'ẏ' => 'ẏ',
+ 'Ẑ' => 'Ẑ',
+ 'ẑ' => 'ẑ',
+ 'Ẓ' => 'Ẓ',
+ 'ẓ' => 'ẓ',
+ 'Ẕ' => 'Ẕ',
+ 'ẕ' => 'ẕ',
+ 'ẖ' => 'ẖ',
+ 'ẗ' => 'ẗ',
+ 'ẘ' => 'ẘ',
+ 'ẙ' => 'ẙ',
+ 'ẛ' => 'ẛ',
+ 'Ạ' => 'Ạ',
+ 'ạ' => 'ạ',
+ 'Ả' => 'Ả',
+ 'ả' => 'ả',
+ 'Ấ' => 'Ấ',
+ 'ấ' => 'ấ',
+ 'Ầ' => 'Ầ',
+ 'ầ' => 'ầ',
+ 'Ẩ' => 'Ẩ',
+ 'ẩ' => 'ẩ',
+ 'Ẫ' => 'Ẫ',
+ 'ẫ' => 'ẫ',
+ 'Ậ' => 'Ậ',
+ 'ậ' => 'ậ',
+ 'Ắ' => 'Ắ',
+ 'ắ' => 'ắ',
+ 'Ằ' => 'Ằ',
+ 'ằ' => 'ằ',
+ 'Ẳ' => 'Ẳ',
+ 'ẳ' => 'ẳ',
+ 'Ẵ' => 'Ẵ',
+ 'ẵ' => 'ẵ',
+ 'Ặ' => 'Ặ',
+ 'ặ' => 'ặ',
+ 'Ẹ' => 'Ẹ',
+ 'ẹ' => 'ẹ',
+ 'Ẻ' => 'Ẻ',
+ 'ẻ' => 'ẻ',
+ 'Ẽ' => 'Ẽ',
+ 'ẽ' => 'ẽ',
+ 'Ế' => 'Ế',
+ 'ế' => 'ế',
+ 'Ề' => 'Ề',
+ 'ề' => 'ề',
+ 'Ể' => 'Ể',
+ 'ể' => 'ể',
+ 'Ễ' => 'Ễ',
+ 'ễ' => 'ễ',
+ 'Ệ' => 'Ệ',
+ 'ệ' => 'ệ',
+ 'Ỉ' => 'Ỉ',
+ 'ỉ' => 'ỉ',
+ 'Ị' => 'Ị',
+ 'ị' => 'ị',
+ 'Ọ' => 'Ọ',
+ 'ọ' => 'ọ',
+ 'Ỏ' => 'Ỏ',
+ 'ỏ' => 'ỏ',
+ 'Ố' => 'Ố',
+ 'ố' => 'ố',
+ 'Ồ' => 'Ồ',
+ 'ồ' => 'ồ',
+ 'Ổ' => 'Ổ',
+ 'ổ' => 'ổ',
+ 'Ỗ' => 'Ỗ',
+ 'ỗ' => 'ỗ',
+ 'Ộ' => 'Ộ',
+ 'ộ' => 'ộ',
+ 'Ớ' => 'Ớ',
+ 'ớ' => 'ớ',
+ 'Ờ' => 'Ờ',
+ 'ờ' => 'ờ',
+ 'Ở' => 'Ở',
+ 'ở' => 'ở',
+ 'Ỡ' => 'Ỡ',
+ 'ỡ' => 'ỡ',
+ 'Ợ' => 'Ợ',
+ 'ợ' => 'ợ',
+ 'Ụ' => 'Ụ',
+ 'ụ' => 'ụ',
+ 'Ủ' => 'Ủ',
+ 'ủ' => 'ủ',
+ 'Ứ' => 'Ứ',
+ 'ứ' => 'ứ',
+ 'Ừ' => 'Ừ',
+ 'ừ' => 'ừ',
+ 'Ử' => 'Ử',
+ 'ử' => 'ử',
+ 'Ữ' => 'Ữ',
+ 'ữ' => 'ữ',
+ 'Ự' => 'Ự',
+ 'ự' => 'ự',
+ 'Ỳ' => 'Ỳ',
+ 'ỳ' => 'ỳ',
+ 'Ỵ' => 'Ỵ',
+ 'ỵ' => 'ỵ',
+ 'Ỷ' => 'Ỷ',
+ 'ỷ' => 'ỷ',
+ 'Ỹ' => 'Ỹ',
+ 'ỹ' => 'ỹ',
+ 'ἀ' => 'ἀ',
+ 'ἁ' => 'ἁ',
+ 'ἂ' => 'ἂ',
+ 'ἃ' => 'ἃ',
+ 'ἄ' => 'ἄ',
+ 'ἅ' => 'ἅ',
+ 'ἆ' => 'ἆ',
+ 'ἇ' => 'ἇ',
+ 'Ἀ' => 'Ἀ',
+ 'Ἁ' => 'Ἁ',
+ 'Ἂ' => 'Ἂ',
+ 'Ἃ' => 'Ἃ',
+ 'Ἄ' => 'Ἄ',
+ 'Ἅ' => 'Ἅ',
+ 'Ἆ' => 'Ἆ',
+ 'Ἇ' => 'Ἇ',
+ 'ἐ' => 'ἐ',
+ 'ἑ' => 'ἑ',
+ 'ἒ' => 'ἒ',
+ 'ἓ' => 'ἓ',
+ 'ἔ' => 'ἔ',
+ 'ἕ' => 'ἕ',
+ 'Ἐ' => 'Ἐ',
+ 'Ἑ' => 'Ἑ',
+ 'Ἒ' => 'Ἒ',
+ 'Ἓ' => 'Ἓ',
+ 'Ἔ' => 'Ἔ',
+ 'Ἕ' => 'Ἕ',
+ 'ἠ' => 'ἠ',
+ 'ἡ' => 'ἡ',
+ 'ἢ' => 'ἢ',
+ 'ἣ' => 'ἣ',
+ 'ἤ' => 'ἤ',
+ 'ἥ' => 'ἥ',
+ 'ἦ' => 'ἦ',
+ 'ἧ' => 'ἧ',
+ 'Ἠ' => 'Ἠ',
+ 'Ἡ' => 'Ἡ',
+ 'Ἢ' => 'Ἢ',
+ 'Ἣ' => 'Ἣ',
+ 'Ἤ' => 'Ἤ',
+ 'Ἥ' => 'Ἥ',
+ 'Ἦ' => 'Ἦ',
+ 'Ἧ' => 'Ἧ',
+ 'ἰ' => 'ἰ',
+ 'ἱ' => 'ἱ',
+ 'ἲ' => 'ἲ',
+ 'ἳ' => 'ἳ',
+ 'ἴ' => 'ἴ',
+ 'ἵ' => 'ἵ',
+ 'ἶ' => 'ἶ',
+ 'ἷ' => 'ἷ',
+ 'Ἰ' => 'Ἰ',
+ 'Ἱ' => 'Ἱ',
+ 'Ἲ' => 'Ἲ',
+ 'Ἳ' => 'Ἳ',
+ 'Ἴ' => 'Ἴ',
+ 'Ἵ' => 'Ἵ',
+ 'Ἶ' => 'Ἶ',
+ 'Ἷ' => 'Ἷ',
+ 'ὀ' => 'ὀ',
+ 'ὁ' => 'ὁ',
+ 'ὂ' => 'ὂ',
+ 'ὃ' => 'ὃ',
+ 'ὄ' => 'ὄ',
+ 'ὅ' => 'ὅ',
+ 'Ὀ' => 'Ὀ',
+ 'Ὁ' => 'Ὁ',
+ 'Ὂ' => 'Ὂ',
+ 'Ὃ' => 'Ὃ',
+ 'Ὄ' => 'Ὄ',
+ 'Ὅ' => 'Ὅ',
+ 'ὐ' => 'ὐ',
+ 'ὑ' => 'ὑ',
+ 'ὒ' => 'ὒ',
+ 'ὓ' => 'ὓ',
+ 'ὔ' => 'ὔ',
+ 'ὕ' => 'ὕ',
+ 'ὖ' => 'ὖ',
+ 'ὗ' => 'ὗ',
+ 'Ὑ' => 'Ὑ',
+ 'Ὓ' => 'Ὓ',
+ 'Ὕ' => 'Ὕ',
+ 'Ὗ' => 'Ὗ',
+ 'ὠ' => 'ὠ',
+ 'ὡ' => 'ὡ',
+ 'ὢ' => 'ὢ',
+ 'ὣ' => 'ὣ',
+ 'ὤ' => 'ὤ',
+ 'ὥ' => 'ὥ',
+ 'ὦ' => 'ὦ',
+ 'ὧ' => 'ὧ',
+ 'Ὠ' => 'Ὠ',
+ 'Ὡ' => 'Ὡ',
+ 'Ὢ' => 'Ὢ',
+ 'Ὣ' => 'Ὣ',
+ 'Ὤ' => 'Ὤ',
+ 'Ὥ' => 'Ὥ',
+ 'Ὦ' => 'Ὦ',
+ 'Ὧ' => 'Ὧ',
+ 'ὰ' => 'ὰ',
+ 'ὲ' => 'ὲ',
+ 'ὴ' => 'ὴ',
+ 'ὶ' => 'ὶ',
+ 'ὸ' => 'ὸ',
+ 'ὺ' => 'ὺ',
+ 'ὼ' => 'ὼ',
+ 'ᾀ' => 'ᾀ',
+ 'ᾁ' => 'ᾁ',
+ 'ᾂ' => 'ᾂ',
+ 'ᾃ' => 'ᾃ',
+ 'ᾄ' => 'ᾄ',
+ 'ᾅ' => 'ᾅ',
+ 'ᾆ' => 'ᾆ',
+ 'ᾇ' => 'ᾇ',
+ 'ᾈ' => 'ᾈ',
+ 'ᾉ' => 'ᾉ',
+ 'ᾊ' => 'ᾊ',
+ 'ᾋ' => 'ᾋ',
+ 'ᾌ' => 'ᾌ',
+ 'ᾍ' => 'ᾍ',
+ 'ᾎ' => 'ᾎ',
+ 'ᾏ' => 'ᾏ',
+ 'ᾐ' => 'ᾐ',
+ 'ᾑ' => 'ᾑ',
+ 'ᾒ' => 'ᾒ',
+ 'ᾓ' => 'ᾓ',
+ 'ᾔ' => 'ᾔ',
+ 'ᾕ' => 'ᾕ',
+ 'ᾖ' => 'ᾖ',
+ 'ᾗ' => 'ᾗ',
+ 'ᾘ' => 'ᾘ',
+ 'ᾙ' => 'ᾙ',
+ 'ᾚ' => 'ᾚ',
+ 'ᾛ' => 'ᾛ',
+ 'ᾜ' => 'ᾜ',
+ 'ᾝ' => 'ᾝ',
+ 'ᾞ' => 'ᾞ',
+ 'ᾟ' => 'ᾟ',
+ 'ᾠ' => 'ᾠ',
+ 'ᾡ' => 'ᾡ',
+ 'ᾢ' => 'ᾢ',
+ 'ᾣ' => 'ᾣ',
+ 'ᾤ' => 'ᾤ',
+ 'ᾥ' => 'ᾥ',
+ 'ᾦ' => 'ᾦ',
+ 'ᾧ' => 'ᾧ',
+ 'ᾨ' => 'ᾨ',
+ 'ᾩ' => 'ᾩ',
+ 'ᾪ' => 'ᾪ',
+ 'ᾫ' => 'ᾫ',
+ 'ᾬ' => 'ᾬ',
+ 'ᾭ' => 'ᾭ',
+ 'ᾮ' => 'ᾮ',
+ 'ᾯ' => 'ᾯ',
+ 'ᾰ' => 'ᾰ',
+ 'ᾱ' => 'ᾱ',
+ 'ᾲ' => 'ᾲ',
+ 'ᾳ' => 'ᾳ',
+ 'ᾴ' => 'ᾴ',
+ 'ᾶ' => 'ᾶ',
+ 'ᾷ' => 'ᾷ',
+ 'Ᾰ' => 'Ᾰ',
+ 'Ᾱ' => 'Ᾱ',
+ 'Ὰ' => 'Ὰ',
+ 'ᾼ' => 'ᾼ',
+ '῁' => '῁',
+ 'ῂ' => 'ῂ',
+ 'ῃ' => 'ῃ',
+ 'ῄ' => 'ῄ',
+ 'ῆ' => 'ῆ',
+ 'ῇ' => 'ῇ',
+ 'Ὲ' => 'Ὲ',
+ 'Ὴ' => 'Ὴ',
+ 'ῌ' => 'ῌ',
+ '῍' => '῍',
+ '῎' => '῎',
+ '῏' => '῏',
+ 'ῐ' => 'ῐ',
+ 'ῑ' => 'ῑ',
+ 'ῒ' => 'ῒ',
+ 'ῖ' => 'ῖ',
+ 'ῗ' => 'ῗ',
+ 'Ῐ' => 'Ῐ',
+ 'Ῑ' => 'Ῑ',
+ 'Ὶ' => 'Ὶ',
+ '῝' => '῝',
+ '῞' => '῞',
+ '῟' => '῟',
+ 'ῠ' => 'ῠ',
+ 'ῡ' => 'ῡ',
+ 'ῢ' => 'ῢ',
+ 'ῤ' => 'ῤ',
+ 'ῥ' => 'ῥ',
+ 'ῦ' => 'ῦ',
+ 'ῧ' => 'ῧ',
+ 'Ῠ' => 'Ῠ',
+ 'Ῡ' => 'Ῡ',
+ 'Ὺ' => 'Ὺ',
+ 'Ῥ' => 'Ῥ',
+ '῭' => '῭',
+ 'ῲ' => 'ῲ',
+ 'ῳ' => 'ῳ',
+ 'ῴ' => 'ῴ',
+ 'ῶ' => 'ῶ',
+ 'ῷ' => 'ῷ',
+ 'Ὸ' => 'Ὸ',
+ 'Ὼ' => 'Ὼ',
+ 'ῼ' => 'ῼ',
+ '↚' => '↚',
+ '↛' => '↛',
+ '↮' => '↮',
+ '⇍' => '⇍',
+ '⇎' => '⇎',
+ '⇏' => '⇏',
+ '∄' => '∄',
+ '∉' => '∉',
+ '∌' => '∌',
+ '∤' => '∤',
+ '∦' => '∦',
+ '≁' => '≁',
+ '≄' => '≄',
+ '≇' => '≇',
+ '≉' => '≉',
+ '≠' => '≠',
+ '≢' => '≢',
+ '≭' => '≭',
+ '≮' => '≮',
+ '≯' => '≯',
+ '≰' => '≰',
+ '≱' => '≱',
+ '≴' => '≴',
+ '≵' => '≵',
+ '≸' => '≸',
+ '≹' => '≹',
+ '⊀' => '⊀',
+ '⊁' => '⊁',
+ '⊄' => '⊄',
+ '⊅' => '⊅',
+ '⊈' => '⊈',
+ '⊉' => '⊉',
+ '⊬' => '⊬',
+ '⊭' => '⊭',
+ '⊮' => '⊮',
+ '⊯' => '⊯',
+ '⋠' => '⋠',
+ '⋡' => '⋡',
+ '⋢' => '⋢',
+ '⋣' => '⋣',
+ '⋪' => '⋪',
+ '⋫' => '⋫',
+ '⋬' => '⋬',
+ '⋭' => '⋭',
+ 'が' => 'が',
+ 'ぎ' => 'ぎ',
+ 'ぐ' => 'ぐ',
+ 'げ' => 'げ',
+ 'ご' => 'ご',
+ 'ざ' => 'ざ',
+ 'じ' => 'じ',
+ 'ず' => 'ず',
+ 'ぜ' => 'ぜ',
+ 'ぞ' => 'ぞ',
+ 'だ' => 'だ',
+ 'ぢ' => 'ぢ',
+ 'づ' => 'づ',
+ 'で' => 'で',
+ 'ど' => 'ど',
+ 'ば' => 'ば',
+ 'ぱ' => 'ぱ',
+ 'び' => 'び',
+ 'ぴ' => 'ぴ',
+ 'ぶ' => 'ぶ',
+ 'ぷ' => 'ぷ',
+ 'べ' => 'べ',
+ 'ぺ' => 'ぺ',
+ 'ぼ' => 'ぼ',
+ 'ぽ' => 'ぽ',
+ 'ゔ' => 'ゔ',
+ 'ゞ' => 'ゞ',
+ 'ガ' => 'ガ',
+ 'ギ' => 'ギ',
+ 'グ' => 'グ',
+ 'ゲ' => 'ゲ',
+ 'ゴ' => 'ゴ',
+ 'ザ' => 'ザ',
+ 'ジ' => 'ジ',
+ 'ズ' => 'ズ',
+ 'ゼ' => 'ゼ',
+ 'ゾ' => 'ゾ',
+ 'ダ' => 'ダ',
+ 'ヂ' => 'ヂ',
+ 'ヅ' => 'ヅ',
+ 'デ' => 'デ',
+ 'ド' => 'ド',
+ 'バ' => 'バ',
+ 'パ' => 'パ',
+ 'ビ' => 'ビ',
+ 'ピ' => 'ピ',
+ 'ブ' => 'ブ',
+ 'プ' => 'プ',
+ 'ベ' => 'ベ',
+ 'ペ' => 'ペ',
+ 'ボ' => 'ボ',
+ 'ポ' => 'ポ',
+ 'ヴ' => 'ヴ',
+ 'ヷ' => 'ヷ',
+ 'ヸ' => 'ヸ',
+ 'ヹ' => 'ヹ',
+ 'ヺ' => 'ヺ',
+ 'ヾ' => 'ヾ',
+ '𑂚' => '𑂚',
+ '𑂜' => '𑂜',
+ '𑂫' => '𑂫',
+ '𑄮' => '𑄮',
+ '𑄯' => '𑄯',
+ '𑍋' => '𑍋',
+ '𑍌' => '𑍌',
+ '𑒻' => '𑒻',
+ '𑒼' => '𑒼',
+ '𑒾' => '𑒾',
+ '𑖺' => '𑖺',
+ '𑖻' => '𑖻',
+ '𑤸' => '𑤸',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php
new file mode 100644
index 0000000..5a3e8e0
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php
@@ -0,0 +1,2065 @@
+<?php
+
+return array (
+ 'À' => 'À',
+ 'Á' => 'Á',
+ 'Â' => 'Â',
+ 'Ã' => 'Ã',
+ 'Ä' => 'Ä',
+ 'Å' => 'Å',
+ 'Ç' => 'Ç',
+ 'È' => 'È',
+ 'É' => 'É',
+ 'Ê' => 'Ê',
+ 'Ë' => 'Ë',
+ 'Ì' => 'Ì',
+ 'Í' => 'Í',
+ 'Î' => 'Î',
+ 'Ï' => 'Ï',
+ 'Ñ' => 'Ñ',
+ 'Ò' => 'Ò',
+ 'Ó' => 'Ó',
+ 'Ô' => 'Ô',
+ 'Õ' => 'Õ',
+ 'Ö' => 'Ö',
+ 'Ù' => 'Ù',
+ 'Ú' => 'Ú',
+ 'Û' => 'Û',
+ 'Ü' => 'Ü',
+ 'Ý' => 'Ý',
+ 'à' => 'à',
+ 'á' => 'á',
+ 'â' => 'â',
+ 'ã' => 'ã',
+ 'ä' => 'ä',
+ 'å' => 'å',
+ 'ç' => 'ç',
+ 'è' => 'è',
+ 'é' => 'é',
+ 'ê' => 'ê',
+ 'ë' => 'ë',
+ 'ì' => 'ì',
+ 'í' => 'í',
+ 'î' => 'î',
+ 'ï' => 'ï',
+ 'ñ' => 'ñ',
+ 'ò' => 'ò',
+ 'ó' => 'ó',
+ 'ô' => 'ô',
+ 'õ' => 'õ',
+ 'ö' => 'ö',
+ 'ù' => 'ù',
+ 'ú' => 'ú',
+ 'û' => 'û',
+ 'ü' => 'ü',
+ 'ý' => 'ý',
+ 'ÿ' => 'ÿ',
+ 'Ā' => 'Ā',
+ 'ā' => 'ā',
+ 'Ă' => 'Ă',
+ 'ă' => 'ă',
+ 'Ą' => 'Ą',
+ 'ą' => 'ą',
+ 'Ć' => 'Ć',
+ 'ć' => 'ć',
+ 'Ĉ' => 'Ĉ',
+ 'ĉ' => 'ĉ',
+ 'Ċ' => 'Ċ',
+ 'ċ' => 'ċ',
+ 'Č' => 'Č',
+ 'č' => 'č',
+ 'Ď' => 'Ď',
+ 'ď' => 'ď',
+ 'Ē' => 'Ē',
+ 'ē' => 'ē',
+ 'Ĕ' => 'Ĕ',
+ 'ĕ' => 'ĕ',
+ 'Ė' => 'Ė',
+ 'ė' => 'ė',
+ 'Ę' => 'Ę',
+ 'ę' => 'ę',
+ 'Ě' => 'Ě',
+ 'ě' => 'ě',
+ 'Ĝ' => 'Ĝ',
+ 'ĝ' => 'ĝ',
+ 'Ğ' => 'Ğ',
+ 'ğ' => 'ğ',
+ 'Ġ' => 'Ġ',
+ 'ġ' => 'ġ',
+ 'Ģ' => 'Ģ',
+ 'ģ' => 'ģ',
+ 'Ĥ' => 'Ĥ',
+ 'ĥ' => 'ĥ',
+ 'Ĩ' => 'Ĩ',
+ 'ĩ' => 'ĩ',
+ 'Ī' => 'Ī',
+ 'ī' => 'ī',
+ 'Ĭ' => 'Ĭ',
+ 'ĭ' => 'ĭ',
+ 'Į' => 'Į',
+ 'į' => 'į',
+ 'İ' => 'İ',
+ 'Ĵ' => 'Ĵ',
+ 'ĵ' => 'ĵ',
+ 'Ķ' => 'Ķ',
+ 'ķ' => 'ķ',
+ 'Ĺ' => 'Ĺ',
+ 'ĺ' => 'ĺ',
+ 'Ļ' => 'Ļ',
+ 'ļ' => 'ļ',
+ 'Ľ' => 'Ľ',
+ 'ľ' => 'ľ',
+ 'Ń' => 'Ń',
+ 'ń' => 'ń',
+ 'Ņ' => 'Ņ',
+ 'ņ' => 'ņ',
+ 'Ň' => 'Ň',
+ 'ň' => 'ň',
+ 'Ō' => 'Ō',
+ 'ō' => 'ō',
+ 'Ŏ' => 'Ŏ',
+ 'ŏ' => 'ŏ',
+ 'Ő' => 'Ő',
+ 'ő' => 'ő',
+ 'Ŕ' => 'Ŕ',
+ 'ŕ' => 'ŕ',
+ 'Ŗ' => 'Ŗ',
+ 'ŗ' => 'ŗ',
+ 'Ř' => 'Ř',
+ 'ř' => 'ř',
+ 'Ś' => 'Ś',
+ 'ś' => 'ś',
+ 'Ŝ' => 'Ŝ',
+ 'ŝ' => 'ŝ',
+ 'Ş' => 'Ş',
+ 'ş' => 'ş',
+ 'Š' => 'Š',
+ 'š' => 'š',
+ 'Ţ' => 'Ţ',
+ 'ţ' => 'ţ',
+ 'Ť' => 'Ť',
+ 'ť' => 'ť',
+ 'Ũ' => 'Ũ',
+ 'ũ' => 'ũ',
+ 'Ū' => 'Ū',
+ 'ū' => 'ū',
+ 'Ŭ' => 'Ŭ',
+ 'ŭ' => 'ŭ',
+ 'Ů' => 'Ů',
+ 'ů' => 'ů',
+ 'Ű' => 'Ű',
+ 'ű' => 'ű',
+ 'Ų' => 'Ų',
+ 'ų' => 'ų',
+ 'Ŵ' => 'Ŵ',
+ 'ŵ' => 'ŵ',
+ 'Ŷ' => 'Ŷ',
+ 'ŷ' => 'ŷ',
+ 'Ÿ' => 'Ÿ',
+ 'Ź' => 'Ź',
+ 'ź' => 'ź',
+ 'Ż' => 'Ż',
+ 'ż' => 'ż',
+ 'Ž' => 'Ž',
+ 'ž' => 'ž',
+ 'Ơ' => 'Ơ',
+ 'ơ' => 'ơ',
+ 'Ư' => 'Ư',
+ 'ư' => 'ư',
+ 'Ǎ' => 'Ǎ',
+ 'ǎ' => 'ǎ',
+ 'Ǐ' => 'Ǐ',
+ 'ǐ' => 'ǐ',
+ 'Ǒ' => 'Ǒ',
+ 'ǒ' => 'ǒ',
+ 'Ǔ' => 'Ǔ',
+ 'ǔ' => 'ǔ',
+ 'Ǖ' => 'Ǖ',
+ 'ǖ' => 'ǖ',
+ 'Ǘ' => 'Ǘ',
+ 'ǘ' => 'ǘ',
+ 'Ǚ' => 'Ǚ',
+ 'ǚ' => 'ǚ',
+ 'Ǜ' => 'Ǜ',
+ 'ǜ' => 'ǜ',
+ 'Ǟ' => 'Ǟ',
+ 'ǟ' => 'ǟ',
+ 'Ǡ' => 'Ǡ',
+ 'ǡ' => 'ǡ',
+ 'Ǣ' => 'Ǣ',
+ 'ǣ' => 'ǣ',
+ 'Ǧ' => 'Ǧ',
+ 'ǧ' => 'ǧ',
+ 'Ǩ' => 'Ǩ',
+ 'ǩ' => 'ǩ',
+ 'Ǫ' => 'Ǫ',
+ 'ǫ' => 'ǫ',
+ 'Ǭ' => 'Ǭ',
+ 'ǭ' => 'ǭ',
+ 'Ǯ' => 'Ǯ',
+ 'ǯ' => 'ǯ',
+ 'ǰ' => 'ǰ',
+ 'Ǵ' => 'Ǵ',
+ 'ǵ' => 'ǵ',
+ 'Ǹ' => 'Ǹ',
+ 'ǹ' => 'ǹ',
+ 'Ǻ' => 'Ǻ',
+ 'ǻ' => 'ǻ',
+ 'Ǽ' => 'Ǽ',
+ 'ǽ' => 'ǽ',
+ 'Ǿ' => 'Ǿ',
+ 'ǿ' => 'ǿ',
+ 'Ȁ' => 'Ȁ',
+ 'ȁ' => 'ȁ',
+ 'Ȃ' => 'Ȃ',
+ 'ȃ' => 'ȃ',
+ 'Ȅ' => 'Ȅ',
+ 'ȅ' => 'ȅ',
+ 'Ȇ' => 'Ȇ',
+ 'ȇ' => 'ȇ',
+ 'Ȉ' => 'Ȉ',
+ 'ȉ' => 'ȉ',
+ 'Ȋ' => 'Ȋ',
+ 'ȋ' => 'ȋ',
+ 'Ȍ' => 'Ȍ',
+ 'ȍ' => 'ȍ',
+ 'Ȏ' => 'Ȏ',
+ 'ȏ' => 'ȏ',
+ 'Ȑ' => 'Ȑ',
+ 'ȑ' => 'ȑ',
+ 'Ȓ' => 'Ȓ',
+ 'ȓ' => 'ȓ',
+ 'Ȕ' => 'Ȕ',
+ 'ȕ' => 'ȕ',
+ 'Ȗ' => 'Ȗ',
+ 'ȗ' => 'ȗ',
+ 'Ș' => 'Ș',
+ 'ș' => 'ș',
+ 'Ț' => 'Ț',
+ 'ț' => 'ț',
+ 'Ȟ' => 'Ȟ',
+ 'ȟ' => 'ȟ',
+ 'Ȧ' => 'Ȧ',
+ 'ȧ' => 'ȧ',
+ 'Ȩ' => 'Ȩ',
+ 'ȩ' => 'ȩ',
+ 'Ȫ' => 'Ȫ',
+ 'ȫ' => 'ȫ',
+ 'Ȭ' => 'Ȭ',
+ 'ȭ' => 'ȭ',
+ 'Ȯ' => 'Ȯ',
+ 'ȯ' => 'ȯ',
+ 'Ȱ' => 'Ȱ',
+ 'ȱ' => 'ȱ',
+ 'Ȳ' => 'Ȳ',
+ 'ȳ' => 'ȳ',
+ '̀' => '̀',
+ '́' => '́',
+ '̓' => '̓',
+ '̈́' => '̈́',
+ 'ʹ' => 'ʹ',
+ ';' => ';',
+ '΅' => '΅',
+ 'Ά' => 'Ά',
+ '·' => '·',
+ 'Έ' => 'Έ',
+ 'Ή' => 'Ή',
+ 'Ί' => 'Ί',
+ 'Ό' => 'Ό',
+ 'Ύ' => 'Ύ',
+ 'Ώ' => 'Ώ',
+ 'ΐ' => 'ΐ',
+ 'Ϊ' => 'Ϊ',
+ 'Ϋ' => 'Ϋ',
+ 'ά' => 'ά',
+ 'έ' => 'έ',
+ 'ή' => 'ή',
+ 'ί' => 'ί',
+ 'ΰ' => 'ΰ',
+ 'ϊ' => 'ϊ',
+ 'ϋ' => 'ϋ',
+ 'ό' => 'ό',
+ 'ύ' => 'ύ',
+ 'ώ' => 'ώ',
+ 'ϓ' => 'ϓ',
+ 'ϔ' => 'ϔ',
+ 'Ѐ' => 'Ѐ',
+ 'Ё' => 'Ё',
+ 'Ѓ' => 'Ѓ',
+ 'Ї' => 'Ї',
+ 'Ќ' => 'Ќ',
+ 'Ѝ' => 'Ѝ',
+ 'Ў' => 'Ў',
+ 'Й' => 'Й',
+ 'й' => 'й',
+ 'ѐ' => 'ѐ',
+ 'ё' => 'ё',
+ 'ѓ' => 'ѓ',
+ 'ї' => 'ї',
+ 'ќ' => 'ќ',
+ 'ѝ' => 'ѝ',
+ 'ў' => 'ў',
+ 'Ѷ' => 'Ѷ',
+ 'ѷ' => 'ѷ',
+ 'Ӂ' => 'Ӂ',
+ 'ӂ' => 'ӂ',
+ 'Ӑ' => 'Ӑ',
+ 'ӑ' => 'ӑ',
+ 'Ӓ' => 'Ӓ',
+ 'ӓ' => 'ӓ',
+ 'Ӗ' => 'Ӗ',
+ 'ӗ' => 'ӗ',
+ 'Ӛ' => 'Ӛ',
+ 'ӛ' => 'ӛ',
+ 'Ӝ' => 'Ӝ',
+ 'ӝ' => 'ӝ',
+ 'Ӟ' => 'Ӟ',
+ 'ӟ' => 'ӟ',
+ 'Ӣ' => 'Ӣ',
+ 'ӣ' => 'ӣ',
+ 'Ӥ' => 'Ӥ',
+ 'ӥ' => 'ӥ',
+ 'Ӧ' => 'Ӧ',
+ 'ӧ' => 'ӧ',
+ 'Ӫ' => 'Ӫ',
+ 'ӫ' => 'ӫ',
+ 'Ӭ' => 'Ӭ',
+ 'ӭ' => 'ӭ',
+ 'Ӯ' => 'Ӯ',
+ 'ӯ' => 'ӯ',
+ 'Ӱ' => 'Ӱ',
+ 'ӱ' => 'ӱ',
+ 'Ӳ' => 'Ӳ',
+ 'ӳ' => 'ӳ',
+ 'Ӵ' => 'Ӵ',
+ 'ӵ' => 'ӵ',
+ 'Ӹ' => 'Ӹ',
+ 'ӹ' => 'ӹ',
+ 'آ' => 'آ',
+ 'أ' => 'أ',
+ 'ؤ' => 'ؤ',
+ 'إ' => 'إ',
+ 'ئ' => 'ئ',
+ 'ۀ' => 'ۀ',
+ 'ۂ' => 'ۂ',
+ 'ۓ' => 'ۓ',
+ 'ऩ' => 'ऩ',
+ 'ऱ' => 'ऱ',
+ 'ऴ' => 'ऴ',
+ 'क़' => 'क़',
+ 'ख़' => 'ख़',
+ 'ग़' => 'ग़',
+ 'ज़' => 'ज़',
+ 'ड़' => 'ड़',
+ 'ढ़' => 'ढ़',
+ 'फ़' => 'फ़',
+ 'य़' => 'य़',
+ 'ো' => 'ো',
+ 'ৌ' => 'ৌ',
+ 'ড়' => 'ড়',
+ 'ঢ়' => 'ঢ়',
+ 'য়' => 'য়',
+ 'ਲ਼' => 'ਲ਼',
+ 'ਸ਼' => 'ਸ਼',
+ 'ਖ਼' => 'ਖ਼',
+ 'ਗ਼' => 'ਗ਼',
+ 'ਜ਼' => 'ਜ਼',
+ 'ਫ਼' => 'ਫ਼',
+ 'ୈ' => 'ୈ',
+ 'ୋ' => 'ୋ',
+ 'ୌ' => 'ୌ',
+ 'ଡ଼' => 'ଡ଼',
+ 'ଢ଼' => 'ଢ଼',
+ 'ஔ' => 'ஔ',
+ 'ொ' => 'ொ',
+ 'ோ' => 'ோ',
+ 'ௌ' => 'ௌ',
+ 'ై' => 'ై',
+ 'ೀ' => 'ೀ',
+ 'ೇ' => 'ೇ',
+ 'ೈ' => 'ೈ',
+ 'ೊ' => 'ೊ',
+ 'ೋ' => 'ೋ',
+ 'ൊ' => 'ൊ',
+ 'ോ' => 'ോ',
+ 'ൌ' => 'ൌ',
+ 'ේ' => 'ේ',
+ 'ො' => 'ො',
+ 'ෝ' => 'ෝ',
+ 'ෞ' => 'ෞ',
+ 'གྷ' => 'གྷ',
+ 'ཌྷ' => 'ཌྷ',
+ 'དྷ' => 'དྷ',
+ 'བྷ' => 'བྷ',
+ 'ཛྷ' => 'ཛྷ',
+ 'ཀྵ' => 'ཀྵ',
+ 'ཱི' => 'ཱི',
+ 'ཱུ' => 'ཱུ',
+ 'ྲྀ' => 'ྲྀ',
+ 'ླྀ' => 'ླྀ',
+ 'ཱྀ' => 'ཱྀ',
+ 'ྒྷ' => 'ྒྷ',
+ 'ྜྷ' => 'ྜྷ',
+ 'ྡྷ' => 'ྡྷ',
+ 'ྦྷ' => 'ྦྷ',
+ 'ྫྷ' => 'ྫྷ',
+ 'ྐྵ' => 'ྐྵ',
+ 'ဦ' => 'ဦ',
+ 'ᬆ' => 'ᬆ',
+ 'ᬈ' => 'ᬈ',
+ 'ᬊ' => 'ᬊ',
+ 'ᬌ' => 'ᬌ',
+ 'ᬎ' => 'ᬎ',
+ 'ᬒ' => 'ᬒ',
+ 'ᬻ' => 'ᬻ',
+ 'ᬽ' => 'ᬽ',
+ 'ᭀ' => 'ᭀ',
+ 'ᭁ' => 'ᭁ',
+ 'ᭃ' => 'ᭃ',
+ 'Ḁ' => 'Ḁ',
+ 'ḁ' => 'ḁ',
+ 'Ḃ' => 'Ḃ',
+ 'ḃ' => 'ḃ',
+ 'Ḅ' => 'Ḅ',
+ 'ḅ' => 'ḅ',
+ 'Ḇ' => 'Ḇ',
+ 'ḇ' => 'ḇ',
+ 'Ḉ' => 'Ḉ',
+ 'ḉ' => 'ḉ',
+ 'Ḋ' => 'Ḋ',
+ 'ḋ' => 'ḋ',
+ 'Ḍ' => 'Ḍ',
+ 'ḍ' => 'ḍ',
+ 'Ḏ' => 'Ḏ',
+ 'ḏ' => 'ḏ',
+ 'Ḑ' => 'Ḑ',
+ 'ḑ' => 'ḑ',
+ 'Ḓ' => 'Ḓ',
+ 'ḓ' => 'ḓ',
+ 'Ḕ' => 'Ḕ',
+ 'ḕ' => 'ḕ',
+ 'Ḗ' => 'Ḗ',
+ 'ḗ' => 'ḗ',
+ 'Ḙ' => 'Ḙ',
+ 'ḙ' => 'ḙ',
+ 'Ḛ' => 'Ḛ',
+ 'ḛ' => 'ḛ',
+ 'Ḝ' => 'Ḝ',
+ 'ḝ' => 'ḝ',
+ 'Ḟ' => 'Ḟ',
+ 'ḟ' => 'ḟ',
+ 'Ḡ' => 'Ḡ',
+ 'ḡ' => 'ḡ',
+ 'Ḣ' => 'Ḣ',
+ 'ḣ' => 'ḣ',
+ 'Ḥ' => 'Ḥ',
+ 'ḥ' => 'ḥ',
+ 'Ḧ' => 'Ḧ',
+ 'ḧ' => 'ḧ',
+ 'Ḩ' => 'Ḩ',
+ 'ḩ' => 'ḩ',
+ 'Ḫ' => 'Ḫ',
+ 'ḫ' => 'ḫ',
+ 'Ḭ' => 'Ḭ',
+ 'ḭ' => 'ḭ',
+ 'Ḯ' => 'Ḯ',
+ 'ḯ' => 'ḯ',
+ 'Ḱ' => 'Ḱ',
+ 'ḱ' => 'ḱ',
+ 'Ḳ' => 'Ḳ',
+ 'ḳ' => 'ḳ',
+ 'Ḵ' => 'Ḵ',
+ 'ḵ' => 'ḵ',
+ 'Ḷ' => 'Ḷ',
+ 'ḷ' => 'ḷ',
+ 'Ḹ' => 'Ḹ',
+ 'ḹ' => 'ḹ',
+ 'Ḻ' => 'Ḻ',
+ 'ḻ' => 'ḻ',
+ 'Ḽ' => 'Ḽ',
+ 'ḽ' => 'ḽ',
+ 'Ḿ' => 'Ḿ',
+ 'ḿ' => 'ḿ',
+ 'Ṁ' => 'Ṁ',
+ 'ṁ' => 'ṁ',
+ 'Ṃ' => 'Ṃ',
+ 'ṃ' => 'ṃ',
+ 'Ṅ' => 'Ṅ',
+ 'ṅ' => 'ṅ',
+ 'Ṇ' => 'Ṇ',
+ 'ṇ' => 'ṇ',
+ 'Ṉ' => 'Ṉ',
+ 'ṉ' => 'ṉ',
+ 'Ṋ' => 'Ṋ',
+ 'ṋ' => 'ṋ',
+ 'Ṍ' => 'Ṍ',
+ 'ṍ' => 'ṍ',
+ 'Ṏ' => 'Ṏ',
+ 'ṏ' => 'ṏ',
+ 'Ṑ' => 'Ṑ',
+ 'ṑ' => 'ṑ',
+ 'Ṓ' => 'Ṓ',
+ 'ṓ' => 'ṓ',
+ 'Ṕ' => 'Ṕ',
+ 'ṕ' => 'ṕ',
+ 'Ṗ' => 'Ṗ',
+ 'ṗ' => 'ṗ',
+ 'Ṙ' => 'Ṙ',
+ 'ṙ' => 'ṙ',
+ 'Ṛ' => 'Ṛ',
+ 'ṛ' => 'ṛ',
+ 'Ṝ' => 'Ṝ',
+ 'ṝ' => 'ṝ',
+ 'Ṟ' => 'Ṟ',
+ 'ṟ' => 'ṟ',
+ 'Ṡ' => 'Ṡ',
+ 'ṡ' => 'ṡ',
+ 'Ṣ' => 'Ṣ',
+ 'ṣ' => 'ṣ',
+ 'Ṥ' => 'Ṥ',
+ 'ṥ' => 'ṥ',
+ 'Ṧ' => 'Ṧ',
+ 'ṧ' => 'ṧ',
+ 'Ṩ' => 'Ṩ',
+ 'ṩ' => 'ṩ',
+ 'Ṫ' => 'Ṫ',
+ 'ṫ' => 'ṫ',
+ 'Ṭ' => 'Ṭ',
+ 'ṭ' => 'ṭ',
+ 'Ṯ' => 'Ṯ',
+ 'ṯ' => 'ṯ',
+ 'Ṱ' => 'Ṱ',
+ 'ṱ' => 'ṱ',
+ 'Ṳ' => 'Ṳ',
+ 'ṳ' => 'ṳ',
+ 'Ṵ' => 'Ṵ',
+ 'ṵ' => 'ṵ',
+ 'Ṷ' => 'Ṷ',
+ 'ṷ' => 'ṷ',
+ 'Ṹ' => 'Ṹ',
+ 'ṹ' => 'ṹ',
+ 'Ṻ' => 'Ṻ',
+ 'ṻ' => 'ṻ',
+ 'Ṽ' => 'Ṽ',
+ 'ṽ' => 'ṽ',
+ 'Ṿ' => 'Ṿ',
+ 'ṿ' => 'ṿ',
+ 'Ẁ' => 'Ẁ',
+ 'ẁ' => 'ẁ',
+ 'Ẃ' => 'Ẃ',
+ 'ẃ' => 'ẃ',
+ 'Ẅ' => 'Ẅ',
+ 'ẅ' => 'ẅ',
+ 'Ẇ' => 'Ẇ',
+ 'ẇ' => 'ẇ',
+ 'Ẉ' => 'Ẉ',
+ 'ẉ' => 'ẉ',
+ 'Ẋ' => 'Ẋ',
+ 'ẋ' => 'ẋ',
+ 'Ẍ' => 'Ẍ',
+ 'ẍ' => 'ẍ',
+ 'Ẏ' => 'Ẏ',
+ 'ẏ' => 'ẏ',
+ 'Ẑ' => 'Ẑ',
+ 'ẑ' => 'ẑ',
+ 'Ẓ' => 'Ẓ',
+ 'ẓ' => 'ẓ',
+ 'Ẕ' => 'Ẕ',
+ 'ẕ' => 'ẕ',
+ 'ẖ' => 'ẖ',
+ 'ẗ' => 'ẗ',
+ 'ẘ' => 'ẘ',
+ 'ẙ' => 'ẙ',
+ 'ẛ' => 'ẛ',
+ 'Ạ' => 'Ạ',
+ 'ạ' => 'ạ',
+ 'Ả' => 'Ả',
+ 'ả' => 'ả',
+ 'Ấ' => 'Ấ',
+ 'ấ' => 'ấ',
+ 'Ầ' => 'Ầ',
+ 'ầ' => 'ầ',
+ 'Ẩ' => 'Ẩ',
+ 'ẩ' => 'ẩ',
+ 'Ẫ' => 'Ẫ',
+ 'ẫ' => 'ẫ',
+ 'Ậ' => 'Ậ',
+ 'ậ' => 'ậ',
+ 'Ắ' => 'Ắ',
+ 'ắ' => 'ắ',
+ 'Ằ' => 'Ằ',
+ 'ằ' => 'ằ',
+ 'Ẳ' => 'Ẳ',
+ 'ẳ' => 'ẳ',
+ 'Ẵ' => 'Ẵ',
+ 'ẵ' => 'ẵ',
+ 'Ặ' => 'Ặ',
+ 'ặ' => 'ặ',
+ 'Ẹ' => 'Ẹ',
+ 'ẹ' => 'ẹ',
+ 'Ẻ' => 'Ẻ',
+ 'ẻ' => 'ẻ',
+ 'Ẽ' => 'Ẽ',
+ 'ẽ' => 'ẽ',
+ 'Ế' => 'Ế',
+ 'ế' => 'ế',
+ 'Ề' => 'Ề',
+ 'ề' => 'ề',
+ 'Ể' => 'Ể',
+ 'ể' => 'ể',
+ 'Ễ' => 'Ễ',
+ 'ễ' => 'ễ',
+ 'Ệ' => 'Ệ',
+ 'ệ' => 'ệ',
+ 'Ỉ' => 'Ỉ',
+ 'ỉ' => 'ỉ',
+ 'Ị' => 'Ị',
+ 'ị' => 'ị',
+ 'Ọ' => 'Ọ',
+ 'ọ' => 'ọ',
+ 'Ỏ' => 'Ỏ',
+ 'ỏ' => 'ỏ',
+ 'Ố' => 'Ố',
+ 'ố' => 'ố',
+ 'Ồ' => 'Ồ',
+ 'ồ' => 'ồ',
+ 'Ổ' => 'Ổ',
+ 'ổ' => 'ổ',
+ 'Ỗ' => 'Ỗ',
+ 'ỗ' => 'ỗ',
+ 'Ộ' => 'Ộ',
+ 'ộ' => 'ộ',
+ 'Ớ' => 'Ớ',
+ 'ớ' => 'ớ',
+ 'Ờ' => 'Ờ',
+ 'ờ' => 'ờ',
+ 'Ở' => 'Ở',
+ 'ở' => 'ở',
+ 'Ỡ' => 'Ỡ',
+ 'ỡ' => 'ỡ',
+ 'Ợ' => 'Ợ',
+ 'ợ' => 'ợ',
+ 'Ụ' => 'Ụ',
+ 'ụ' => 'ụ',
+ 'Ủ' => 'Ủ',
+ 'ủ' => 'ủ',
+ 'Ứ' => 'Ứ',
+ 'ứ' => 'ứ',
+ 'Ừ' => 'Ừ',
+ 'ừ' => 'ừ',
+ 'Ử' => 'Ử',
+ 'ử' => 'ử',
+ 'Ữ' => 'Ữ',
+ 'ữ' => 'ữ',
+ 'Ự' => 'Ự',
+ 'ự' => 'ự',
+ 'Ỳ' => 'Ỳ',
+ 'ỳ' => 'ỳ',
+ 'Ỵ' => 'Ỵ',
+ 'ỵ' => 'ỵ',
+ 'Ỷ' => 'Ỷ',
+ 'ỷ' => 'ỷ',
+ 'Ỹ' => 'Ỹ',
+ 'ỹ' => 'ỹ',
+ 'ἀ' => 'ἀ',
+ 'ἁ' => 'ἁ',
+ 'ἂ' => 'ἂ',
+ 'ἃ' => 'ἃ',
+ 'ἄ' => 'ἄ',
+ 'ἅ' => 'ἅ',
+ 'ἆ' => 'ἆ',
+ 'ἇ' => 'ἇ',
+ 'Ἀ' => 'Ἀ',
+ 'Ἁ' => 'Ἁ',
+ 'Ἂ' => 'Ἂ',
+ 'Ἃ' => 'Ἃ',
+ 'Ἄ' => 'Ἄ',
+ 'Ἅ' => 'Ἅ',
+ 'Ἆ' => 'Ἆ',
+ 'Ἇ' => 'Ἇ',
+ 'ἐ' => 'ἐ',
+ 'ἑ' => 'ἑ',
+ 'ἒ' => 'ἒ',
+ 'ἓ' => 'ἓ',
+ 'ἔ' => 'ἔ',
+ 'ἕ' => 'ἕ',
+ 'Ἐ' => 'Ἐ',
+ 'Ἑ' => 'Ἑ',
+ 'Ἒ' => 'Ἒ',
+ 'Ἓ' => 'Ἓ',
+ 'Ἔ' => 'Ἔ',
+ 'Ἕ' => 'Ἕ',
+ 'ἠ' => 'ἠ',
+ 'ἡ' => 'ἡ',
+ 'ἢ' => 'ἢ',
+ 'ἣ' => 'ἣ',
+ 'ἤ' => 'ἤ',
+ 'ἥ' => 'ἥ',
+ 'ἦ' => 'ἦ',
+ 'ἧ' => 'ἧ',
+ 'Ἠ' => 'Ἠ',
+ 'Ἡ' => 'Ἡ',
+ 'Ἢ' => 'Ἢ',
+ 'Ἣ' => 'Ἣ',
+ 'Ἤ' => 'Ἤ',
+ 'Ἥ' => 'Ἥ',
+ 'Ἦ' => 'Ἦ',
+ 'Ἧ' => 'Ἧ',
+ 'ἰ' => 'ἰ',
+ 'ἱ' => 'ἱ',
+ 'ἲ' => 'ἲ',
+ 'ἳ' => 'ἳ',
+ 'ἴ' => 'ἴ',
+ 'ἵ' => 'ἵ',
+ 'ἶ' => 'ἶ',
+ 'ἷ' => 'ἷ',
+ 'Ἰ' => 'Ἰ',
+ 'Ἱ' => 'Ἱ',
+ 'Ἲ' => 'Ἲ',
+ 'Ἳ' => 'Ἳ',
+ 'Ἴ' => 'Ἴ',
+ 'Ἵ' => 'Ἵ',
+ 'Ἶ' => 'Ἶ',
+ 'Ἷ' => 'Ἷ',
+ 'ὀ' => 'ὀ',
+ 'ὁ' => 'ὁ',
+ 'ὂ' => 'ὂ',
+ 'ὃ' => 'ὃ',
+ 'ὄ' => 'ὄ',
+ 'ὅ' => 'ὅ',
+ 'Ὀ' => 'Ὀ',
+ 'Ὁ' => 'Ὁ',
+ 'Ὂ' => 'Ὂ',
+ 'Ὃ' => 'Ὃ',
+ 'Ὄ' => 'Ὄ',
+ 'Ὅ' => 'Ὅ',
+ 'ὐ' => 'ὐ',
+ 'ὑ' => 'ὑ',
+ 'ὒ' => 'ὒ',
+ 'ὓ' => 'ὓ',
+ 'ὔ' => 'ὔ',
+ 'ὕ' => 'ὕ',
+ 'ὖ' => 'ὖ',
+ 'ὗ' => 'ὗ',
+ 'Ὑ' => 'Ὑ',
+ 'Ὓ' => 'Ὓ',
+ 'Ὕ' => 'Ὕ',
+ 'Ὗ' => 'Ὗ',
+ 'ὠ' => 'ὠ',
+ 'ὡ' => 'ὡ',
+ 'ὢ' => 'ὢ',
+ 'ὣ' => 'ὣ',
+ 'ὤ' => 'ὤ',
+ 'ὥ' => 'ὥ',
+ 'ὦ' => 'ὦ',
+ 'ὧ' => 'ὧ',
+ 'Ὠ' => 'Ὠ',
+ 'Ὡ' => 'Ὡ',
+ 'Ὢ' => 'Ὢ',
+ 'Ὣ' => 'Ὣ',
+ 'Ὤ' => 'Ὤ',
+ 'Ὥ' => 'Ὥ',
+ 'Ὦ' => 'Ὦ',
+ 'Ὧ' => 'Ὧ',
+ 'ὰ' => 'ὰ',
+ 'ά' => 'ά',
+ 'ὲ' => 'ὲ',
+ 'έ' => 'έ',
+ 'ὴ' => 'ὴ',
+ 'ή' => 'ή',
+ 'ὶ' => 'ὶ',
+ 'ί' => 'ί',
+ 'ὸ' => 'ὸ',
+ 'ό' => 'ό',
+ 'ὺ' => 'ὺ',
+ 'ύ' => 'ύ',
+ 'ὼ' => 'ὼ',
+ 'ώ' => 'ώ',
+ 'ᾀ' => 'ᾀ',
+ 'ᾁ' => 'ᾁ',
+ 'ᾂ' => 'ᾂ',
+ 'ᾃ' => 'ᾃ',
+ 'ᾄ' => 'ᾄ',
+ 'ᾅ' => 'ᾅ',
+ 'ᾆ' => 'ᾆ',
+ 'ᾇ' => 'ᾇ',
+ 'ᾈ' => 'ᾈ',
+ 'ᾉ' => 'ᾉ',
+ 'ᾊ' => 'ᾊ',
+ 'ᾋ' => 'ᾋ',
+ 'ᾌ' => 'ᾌ',
+ 'ᾍ' => 'ᾍ',
+ 'ᾎ' => 'ᾎ',
+ 'ᾏ' => 'ᾏ',
+ 'ᾐ' => 'ᾐ',
+ 'ᾑ' => 'ᾑ',
+ 'ᾒ' => 'ᾒ',
+ 'ᾓ' => 'ᾓ',
+ 'ᾔ' => 'ᾔ',
+ 'ᾕ' => 'ᾕ',
+ 'ᾖ' => 'ᾖ',
+ 'ᾗ' => 'ᾗ',
+ 'ᾘ' => 'ᾘ',
+ 'ᾙ' => 'ᾙ',
+ 'ᾚ' => 'ᾚ',
+ 'ᾛ' => 'ᾛ',
+ 'ᾜ' => 'ᾜ',
+ 'ᾝ' => 'ᾝ',
+ 'ᾞ' => 'ᾞ',
+ 'ᾟ' => 'ᾟ',
+ 'ᾠ' => 'ᾠ',
+ 'ᾡ' => 'ᾡ',
+ 'ᾢ' => 'ᾢ',
+ 'ᾣ' => 'ᾣ',
+ 'ᾤ' => 'ᾤ',
+ 'ᾥ' => 'ᾥ',
+ 'ᾦ' => 'ᾦ',
+ 'ᾧ' => 'ᾧ',
+ 'ᾨ' => 'ᾨ',
+ 'ᾩ' => 'ᾩ',
+ 'ᾪ' => 'ᾪ',
+ 'ᾫ' => 'ᾫ',
+ 'ᾬ' => 'ᾬ',
+ 'ᾭ' => 'ᾭ',
+ 'ᾮ' => 'ᾮ',
+ 'ᾯ' => 'ᾯ',
+ 'ᾰ' => 'ᾰ',
+ 'ᾱ' => 'ᾱ',
+ 'ᾲ' => 'ᾲ',
+ 'ᾳ' => 'ᾳ',
+ 'ᾴ' => 'ᾴ',
+ 'ᾶ' => 'ᾶ',
+ 'ᾷ' => 'ᾷ',
+ 'Ᾰ' => 'Ᾰ',
+ 'Ᾱ' => 'Ᾱ',
+ 'Ὰ' => 'Ὰ',
+ 'Ά' => 'Ά',
+ 'ᾼ' => 'ᾼ',
+ 'ι' => 'ι',
+ '῁' => '῁',
+ 'ῂ' => 'ῂ',
+ 'ῃ' => 'ῃ',
+ 'ῄ' => 'ῄ',
+ 'ῆ' => 'ῆ',
+ 'ῇ' => 'ῇ',
+ 'Ὲ' => 'Ὲ',
+ 'Έ' => 'Έ',
+ 'Ὴ' => 'Ὴ',
+ 'Ή' => 'Ή',
+ 'ῌ' => 'ῌ',
+ '῍' => '῍',
+ '῎' => '῎',
+ '῏' => '῏',
+ 'ῐ' => 'ῐ',
+ 'ῑ' => 'ῑ',
+ 'ῒ' => 'ῒ',
+ 'ΐ' => 'ΐ',
+ 'ῖ' => 'ῖ',
+ 'ῗ' => 'ῗ',
+ 'Ῐ' => 'Ῐ',
+ 'Ῑ' => 'Ῑ',
+ 'Ὶ' => 'Ὶ',
+ 'Ί' => 'Ί',
+ '῝' => '῝',
+ '῞' => '῞',
+ '῟' => '῟',
+ 'ῠ' => 'ῠ',
+ 'ῡ' => 'ῡ',
+ 'ῢ' => 'ῢ',
+ 'ΰ' => 'ΰ',
+ 'ῤ' => 'ῤ',
+ 'ῥ' => 'ῥ',
+ 'ῦ' => 'ῦ',
+ 'ῧ' => 'ῧ',
+ 'Ῠ' => 'Ῠ',
+ 'Ῡ' => 'Ῡ',
+ 'Ὺ' => 'Ὺ',
+ 'Ύ' => 'Ύ',
+ 'Ῥ' => 'Ῥ',
+ '῭' => '῭',
+ '΅' => '΅',
+ '`' => '`',
+ 'ῲ' => 'ῲ',
+ 'ῳ' => 'ῳ',
+ 'ῴ' => 'ῴ',
+ 'ῶ' => 'ῶ',
+ 'ῷ' => 'ῷ',
+ 'Ὸ' => 'Ὸ',
+ 'Ό' => 'Ό',
+ 'Ὼ' => 'Ὼ',
+ 'Ώ' => 'Ώ',
+ 'ῼ' => 'ῼ',
+ '´' => '´',
+ ' ' => ' ',
+ ' ' => ' ',
+ 'Ω' => 'Ω',
+ 'K' => 'K',
+ 'Å' => 'Å',
+ '↚' => '↚',
+ '↛' => '↛',
+ '↮' => '↮',
+ '⇍' => '⇍',
+ '⇎' => '⇎',
+ '⇏' => '⇏',
+ '∄' => '∄',
+ '∉' => '∉',
+ '∌' => '∌',
+ '∤' => '∤',
+ '∦' => '∦',
+ '≁' => '≁',
+ '≄' => '≄',
+ '≇' => '≇',
+ '≉' => '≉',
+ '≠' => '≠',
+ '≢' => '≢',
+ '≭' => '≭',
+ '≮' => '≮',
+ '≯' => '≯',
+ '≰' => '≰',
+ '≱' => '≱',
+ '≴' => '≴',
+ '≵' => '≵',
+ '≸' => '≸',
+ '≹' => '≹',
+ '⊀' => '⊀',
+ '⊁' => '⊁',
+ '⊄' => '⊄',
+ '⊅' => '⊅',
+ '⊈' => '⊈',
+ '⊉' => '⊉',
+ '⊬' => '⊬',
+ '⊭' => '⊭',
+ '⊮' => '⊮',
+ '⊯' => '⊯',
+ '⋠' => '⋠',
+ '⋡' => '⋡',
+ '⋢' => '⋢',
+ '⋣' => '⋣',
+ '⋪' => '⋪',
+ '⋫' => '⋫',
+ '⋬' => '⋬',
+ '⋭' => '⋭',
+ '〈' => '〈',
+ '〉' => '〉',
+ '⫝̸' => '⫝̸',
+ 'が' => 'が',
+ 'ぎ' => 'ぎ',
+ 'ぐ' => 'ぐ',
+ 'げ' => 'げ',
+ 'ご' => 'ご',
+ 'ざ' => 'ざ',
+ 'じ' => 'じ',
+ 'ず' => 'ず',
+ 'ぜ' => 'ぜ',
+ 'ぞ' => 'ぞ',
+ 'だ' => 'だ',
+ 'ぢ' => 'ぢ',
+ 'づ' => 'づ',
+ 'で' => 'で',
+ 'ど' => 'ど',
+ 'ば' => 'ば',
+ 'ぱ' => 'ぱ',
+ 'び' => 'び',
+ 'ぴ' => 'ぴ',
+ 'ぶ' => 'ぶ',
+ 'ぷ' => 'ぷ',
+ 'べ' => 'べ',
+ 'ぺ' => 'ぺ',
+ 'ぼ' => 'ぼ',
+ 'ぽ' => 'ぽ',
+ 'ゔ' => 'ゔ',
+ 'ゞ' => 'ゞ',
+ 'ガ' => 'ガ',
+ 'ギ' => 'ギ',
+ 'グ' => 'グ',
+ 'ゲ' => 'ゲ',
+ 'ゴ' => 'ゴ',
+ 'ザ' => 'ザ',
+ 'ジ' => 'ジ',
+ 'ズ' => 'ズ',
+ 'ゼ' => 'ゼ',
+ 'ゾ' => 'ゾ',
+ 'ダ' => 'ダ',
+ 'ヂ' => 'ヂ',
+ 'ヅ' => 'ヅ',
+ 'デ' => 'デ',
+ 'ド' => 'ド',
+ 'バ' => 'バ',
+ 'パ' => 'パ',
+ 'ビ' => 'ビ',
+ 'ピ' => 'ピ',
+ 'ブ' => 'ブ',
+ 'プ' => 'プ',
+ 'ベ' => 'ベ',
+ 'ペ' => 'ペ',
+ 'ボ' => 'ボ',
+ 'ポ' => 'ポ',
+ 'ヴ' => 'ヴ',
+ 'ヷ' => 'ヷ',
+ 'ヸ' => 'ヸ',
+ 'ヹ' => 'ヹ',
+ 'ヺ' => 'ヺ',
+ 'ヾ' => 'ヾ',
+ '豈' => '豈',
+ '更' => '更',
+ '車' => '車',
+ '賈' => '賈',
+ '滑' => '滑',
+ '串' => '串',
+ '句' => '句',
+ '龜' => '龜',
+ '龜' => '龜',
+ '契' => '契',
+ '金' => '金',
+ '喇' => '喇',
+ '奈' => '奈',
+ '懶' => '懶',
+ '癩' => '癩',
+ '羅' => '羅',
+ '蘿' => '蘿',
+ '螺' => '螺',
+ '裸' => '裸',
+ '邏' => '邏',
+ '樂' => '樂',
+ '洛' => '洛',
+ '烙' => '烙',
+ '珞' => '珞',
+ '落' => '落',
+ '酪' => '酪',
+ '駱' => '駱',
+ '亂' => '亂',
+ '卵' => '卵',
+ '欄' => '欄',
+ '爛' => '爛',
+ '蘭' => '蘭',
+ '鸞' => '鸞',
+ '嵐' => '嵐',
+ '濫' => '濫',
+ '藍' => '藍',
+ '襤' => '襤',
+ '拉' => '拉',
+ '臘' => '臘',
+ '蠟' => '蠟',
+ '廊' => '廊',
+ '朗' => '朗',
+ '浪' => '浪',
+ '狼' => '狼',
+ '郎' => '郎',
+ '來' => '來',
+ '冷' => '冷',
+ '勞' => '勞',
+ '擄' => '擄',
+ '櫓' => '櫓',
+ '爐' => '爐',
+ '盧' => '盧',
+ '老' => '老',
+ '蘆' => '蘆',
+ '虜' => '虜',
+ '路' => '路',
+ '露' => '露',
+ '魯' => '魯',
+ '鷺' => '鷺',
+ '碌' => '碌',
+ '祿' => '祿',
+ '綠' => '綠',
+ '菉' => '菉',
+ '錄' => '錄',
+ '鹿' => '鹿',
+ '論' => '論',
+ '壟' => '壟',
+ '弄' => '弄',
+ '籠' => '籠',
+ '聾' => '聾',
+ '牢' => '牢',
+ '磊' => '磊',
+ '賂' => '賂',
+ '雷' => '雷',
+ '壘' => '壘',
+ '屢' => '屢',
+ '樓' => '樓',
+ '淚' => '淚',
+ '漏' => '漏',
+ '累' => '累',
+ '縷' => '縷',
+ '陋' => '陋',
+ '勒' => '勒',
+ '肋' => '肋',
+ '凜' => '凜',
+ '凌' => '凌',
+ '稜' => '稜',
+ '綾' => '綾',
+ '菱' => '菱',
+ '陵' => '陵',
+ '讀' => '讀',
+ '拏' => '拏',
+ '樂' => '樂',
+ '諾' => '諾',
+ '丹' => '丹',
+ '寧' => '寧',
+ '怒' => '怒',
+ '率' => '率',
+ '異' => '異',
+ '北' => '北',
+ '磻' => '磻',
+ '便' => '便',
+ '復' => '復',
+ '不' => '不',
+ '泌' => '泌',
+ '數' => '數',
+ '索' => '索',
+ '參' => '參',
+ '塞' => '塞',
+ '省' => '省',
+ '葉' => '葉',
+ '說' => '說',
+ '殺' => '殺',
+ '辰' => '辰',
+ '沈' => '沈',
+ '拾' => '拾',
+ '若' => '若',
+ '掠' => '掠',
+ '略' => '略',
+ '亮' => '亮',
+ '兩' => '兩',
+ '凉' => '凉',
+ '梁' => '梁',
+ '糧' => '糧',
+ '良' => '良',
+ '諒' => '諒',
+ '量' => '量',
+ '勵' => '勵',
+ '呂' => '呂',
+ '女' => '女',
+ '廬' => '廬',
+ '旅' => '旅',
+ '濾' => '濾',
+ '礪' => '礪',
+ '閭' => '閭',
+ '驪' => '驪',
+ '麗' => '麗',
+ '黎' => '黎',
+ '力' => '力',
+ '曆' => '曆',
+ '歷' => '歷',
+ '轢' => '轢',
+ '年' => '年',
+ '憐' => '憐',
+ '戀' => '戀',
+ '撚' => '撚',
+ '漣' => '漣',
+ '煉' => '煉',
+ '璉' => '璉',
+ '秊' => '秊',
+ '練' => '練',
+ '聯' => '聯',
+ '輦' => '輦',
+ '蓮' => '蓮',
+ '連' => '連',
+ '鍊' => '鍊',
+ '列' => '列',
+ '劣' => '劣',
+ '咽' => '咽',
+ '烈' => '烈',
+ '裂' => '裂',
+ '說' => '說',
+ '廉' => '廉',
+ '念' => '念',
+ '捻' => '捻',
+ '殮' => '殮',
+ '簾' => '簾',
+ '獵' => '獵',
+ '令' => '令',
+ '囹' => '囹',
+ '寧' => '寧',
+ '嶺' => '嶺',
+ '怜' => '怜',
+ '玲' => '玲',
+ '瑩' => '瑩',
+ '羚' => '羚',
+ '聆' => '聆',
+ '鈴' => '鈴',
+ '零' => '零',
+ '靈' => '靈',
+ '領' => '領',
+ '例' => '例',
+ '禮' => '禮',
+ '醴' => '醴',
+ '隸' => '隸',
+ '惡' => '惡',
+ '了' => '了',
+ '僚' => '僚',
+ '寮' => '寮',
+ '尿' => '尿',
+ '料' => '料',
+ '樂' => '樂',
+ '燎' => '燎',
+ '療' => '療',
+ '蓼' => '蓼',
+ '遼' => '遼',
+ '龍' => '龍',
+ '暈' => '暈',
+ '阮' => '阮',
+ '劉' => '劉',
+ '杻' => '杻',
+ '柳' => '柳',
+ '流' => '流',
+ '溜' => '溜',
+ '琉' => '琉',
+ '留' => '留',
+ '硫' => '硫',
+ '紐' => '紐',
+ '類' => '類',
+ '六' => '六',
+ '戮' => '戮',
+ '陸' => '陸',
+ '倫' => '倫',
+ '崙' => '崙',
+ '淪' => '淪',
+ '輪' => '輪',
+ '律' => '律',
+ '慄' => '慄',
+ '栗' => '栗',
+ '率' => '率',
+ '隆' => '隆',
+ '利' => '利',
+ '吏' => '吏',
+ '履' => '履',
+ '易' => '易',
+ '李' => '李',
+ '梨' => '梨',
+ '泥' => '泥',
+ '理' => '理',
+ '痢' => '痢',
+ '罹' => '罹',
+ '裏' => '裏',
+ '裡' => '裡',
+ '里' => '里',
+ '離' => '離',
+ '匿' => '匿',
+ '溺' => '溺',
+ '吝' => '吝',
+ '燐' => '燐',
+ '璘' => '璘',
+ '藺' => '藺',
+ '隣' => '隣',
+ '鱗' => '鱗',
+ '麟' => '麟',
+ '林' => '林',
+ '淋' => '淋',
+ '臨' => '臨',
+ '立' => '立',
+ '笠' => '笠',
+ '粒' => '粒',
+ '狀' => '狀',
+ '炙' => '炙',
+ '識' => '識',
+ '什' => '什',
+ '茶' => '茶',
+ '刺' => '刺',
+ '切' => '切',
+ '度' => '度',
+ '拓' => '拓',
+ '糖' => '糖',
+ '宅' => '宅',
+ '洞' => '洞',
+ '暴' => '暴',
+ '輻' => '輻',
+ '行' => '行',
+ '降' => '降',
+ '見' => '見',
+ '廓' => '廓',
+ '兀' => '兀',
+ '嗀' => '嗀',
+ '塚' => '塚',
+ '晴' => '晴',
+ '凞' => '凞',
+ '猪' => '猪',
+ '益' => '益',
+ '礼' => '礼',
+ '神' => '神',
+ '祥' => '祥',
+ '福' => '福',
+ '靖' => '靖',
+ '精' => '精',
+ '羽' => '羽',
+ '蘒' => '蘒',
+ '諸' => '諸',
+ '逸' => '逸',
+ '都' => '都',
+ '飯' => '飯',
+ '飼' => '飼',
+ '館' => '館',
+ '鶴' => '鶴',
+ '郞' => '郞',
+ '隷' => '隷',
+ '侮' => '侮',
+ '僧' => '僧',
+ '免' => '免',
+ '勉' => '勉',
+ '勤' => '勤',
+ '卑' => '卑',
+ '喝' => '喝',
+ '嘆' => '嘆',
+ '器' => '器',
+ '塀' => '塀',
+ '墨' => '墨',
+ '層' => '層',
+ '屮' => '屮',
+ '悔' => '悔',
+ '慨' => '慨',
+ '憎' => '憎',
+ '懲' => '懲',
+ '敏' => '敏',
+ '既' => '既',
+ '暑' => '暑',
+ '梅' => '梅',
+ '海' => '海',
+ '渚' => '渚',
+ '漢' => '漢',
+ '煮' => '煮',
+ '爫' => '爫',
+ '琢' => '琢',
+ '碑' => '碑',
+ '社' => '社',
+ '祉' => '祉',
+ '祈' => '祈',
+ '祐' => '祐',
+ '祖' => '祖',
+ '祝' => '祝',
+ '禍' => '禍',
+ '禎' => '禎',
+ '穀' => '穀',
+ '突' => '突',
+ '節' => '節',
+ '練' => '練',
+ '縉' => '縉',
+ '繁' => '繁',
+ '署' => '署',
+ '者' => '者',
+ '臭' => '臭',
+ '艹' => '艹',
+ '艹' => '艹',
+ '著' => '著',
+ '褐' => '褐',
+ '視' => '視',
+ '謁' => '謁',
+ '謹' => '謹',
+ '賓' => '賓',
+ '贈' => '贈',
+ '辶' => '辶',
+ '逸' => '逸',
+ '難' => '難',
+ '響' => '響',
+ '頻' => '頻',
+ '恵' => '恵',
+ '𤋮' => '𤋮',
+ '舘' => '舘',
+ '並' => '並',
+ '况' => '况',
+ '全' => '全',
+ '侀' => '侀',
+ '充' => '充',
+ '冀' => '冀',
+ '勇' => '勇',
+ '勺' => '勺',
+ '喝' => '喝',
+ '啕' => '啕',
+ '喙' => '喙',
+ '嗢' => '嗢',
+ '塚' => '塚',
+ '墳' => '墳',
+ '奄' => '奄',
+ '奔' => '奔',
+ '婢' => '婢',
+ '嬨' => '嬨',
+ '廒' => '廒',
+ '廙' => '廙',
+ '彩' => '彩',
+ '徭' => '徭',
+ '惘' => '惘',
+ '慎' => '慎',
+ '愈' => '愈',
+ '憎' => '憎',
+ '慠' => '慠',
+ '懲' => '懲',
+ '戴' => '戴',
+ '揄' => '揄',
+ '搜' => '搜',
+ '摒' => '摒',
+ '敖' => '敖',
+ '晴' => '晴',
+ '朗' => '朗',
+ '望' => '望',
+ '杖' => '杖',
+ '歹' => '歹',
+ '殺' => '殺',
+ '流' => '流',
+ '滛' => '滛',
+ '滋' => '滋',
+ '漢' => '漢',
+ '瀞' => '瀞',
+ '煮' => '煮',
+ '瞧' => '瞧',
+ '爵' => '爵',
+ '犯' => '犯',
+ '猪' => '猪',
+ '瑱' => '瑱',
+ '甆' => '甆',
+ '画' => '画',
+ '瘝' => '瘝',
+ '瘟' => '瘟',
+ '益' => '益',
+ '盛' => '盛',
+ '直' => '直',
+ '睊' => '睊',
+ '着' => '着',
+ '磌' => '磌',
+ '窱' => '窱',
+ '節' => '節',
+ '类' => '类',
+ '絛' => '絛',
+ '練' => '練',
+ '缾' => '缾',
+ '者' => '者',
+ '荒' => '荒',
+ '華' => '華',
+ '蝹' => '蝹',
+ '襁' => '襁',
+ '覆' => '覆',
+ '視' => '視',
+ '調' => '調',
+ '諸' => '諸',
+ '請' => '請',
+ '謁' => '謁',
+ '諾' => '諾',
+ '諭' => '諭',
+ '謹' => '謹',
+ '變' => '變',
+ '贈' => '贈',
+ '輸' => '輸',
+ '遲' => '遲',
+ '醙' => '醙',
+ '鉶' => '鉶',
+ '陼' => '陼',
+ '難' => '難',
+ '靖' => '靖',
+ '韛' => '韛',
+ '響' => '響',
+ '頋' => '頋',
+ '頻' => '頻',
+ '鬒' => '鬒',
+ '龜' => '龜',
+ '𢡊' => '𢡊',
+ '𢡄' => '𢡄',
+ '𣏕' => '𣏕',
+ '㮝' => '㮝',
+ '䀘' => '䀘',
+ '䀹' => '䀹',
+ '𥉉' => '𥉉',
+ '𥳐' => '𥳐',
+ '𧻓' => '𧻓',
+ '齃' => '齃',
+ '龎' => '龎',
+ 'יִ' => 'יִ',
+ 'ײַ' => 'ײַ',
+ 'שׁ' => 'שׁ',
+ 'שׂ' => 'שׂ',
+ 'שּׁ' => 'שּׁ',
+ 'שּׂ' => 'שּׂ',
+ 'אַ' => 'אַ',
+ 'אָ' => 'אָ',
+ 'אּ' => 'אּ',
+ 'בּ' => 'בּ',
+ 'גּ' => 'גּ',
+ 'דּ' => 'דּ',
+ 'הּ' => 'הּ',
+ 'וּ' => 'וּ',
+ 'זּ' => 'זּ',
+ 'טּ' => 'טּ',
+ 'יּ' => 'יּ',
+ 'ךּ' => 'ךּ',
+ 'כּ' => 'כּ',
+ 'לּ' => 'לּ',
+ 'מּ' => 'מּ',
+ 'נּ' => 'נּ',
+ 'סּ' => 'סּ',
+ 'ףּ' => 'ףּ',
+ 'פּ' => 'פּ',
+ 'צּ' => 'צּ',
+ 'קּ' => 'קּ',
+ 'רּ' => 'רּ',
+ 'שּ' => 'שּ',
+ 'תּ' => 'תּ',
+ 'וֹ' => 'וֹ',
+ 'בֿ' => 'בֿ',
+ 'כֿ' => 'כֿ',
+ 'פֿ' => 'פֿ',
+ '𑂚' => '𑂚',
+ '𑂜' => '𑂜',
+ '𑂫' => '𑂫',
+ '𑄮' => '𑄮',
+ '𑄯' => '𑄯',
+ '𑍋' => '𑍋',
+ '𑍌' => '𑍌',
+ '𑒻' => '𑒻',
+ '𑒼' => '𑒼',
+ '𑒾' => '𑒾',
+ '𑖺' => '𑖺',
+ '𑖻' => '𑖻',
+ '𑤸' => '𑤸',
+ '𝅗𝅥' => '𝅗𝅥',
+ '𝅘𝅥' => '𝅘𝅥',
+ '𝅘𝅥𝅮' => '𝅘𝅥𝅮',
+ '𝅘𝅥𝅯' => '𝅘𝅥𝅯',
+ '𝅘𝅥𝅰' => '𝅘𝅥𝅰',
+ '𝅘𝅥𝅱' => '𝅘𝅥𝅱',
+ '𝅘𝅥𝅲' => '𝅘𝅥𝅲',
+ '𝆹𝅥' => '𝆹𝅥',
+ '𝆺𝅥' => '𝆺𝅥',
+ '𝆹𝅥𝅮' => '𝆹𝅥𝅮',
+ '𝆺𝅥𝅮' => '𝆺𝅥𝅮',
+ '𝆹𝅥𝅯' => '𝆹𝅥𝅯',
+ '𝆺𝅥𝅯' => '𝆺𝅥𝅯',
+ '丽' => '丽',
+ '丸' => '丸',
+ '乁' => '乁',
+ '𠄢' => '𠄢',
+ '你' => '你',
+ '侮' => '侮',
+ '侻' => '侻',
+ '倂' => '倂',
+ '偺' => '偺',
+ '備' => '備',
+ '僧' => '僧',
+ '像' => '像',
+ '㒞' => '㒞',
+ '𠘺' => '𠘺',
+ '免' => '免',
+ '兔' => '兔',
+ '兤' => '兤',
+ '具' => '具',
+ '𠔜' => '𠔜',
+ '㒹' => '㒹',
+ '內' => '內',
+ '再' => '再',
+ '𠕋' => '𠕋',
+ '冗' => '冗',
+ '冤' => '冤',
+ '仌' => '仌',
+ '冬' => '冬',
+ '况' => '况',
+ '𩇟' => '𩇟',
+ '凵' => '凵',
+ '刃' => '刃',
+ '㓟' => '㓟',
+ '刻' => '刻',
+ '剆' => '剆',
+ '割' => '割',
+ '剷' => '剷',
+ '㔕' => '㔕',
+ '勇' => '勇',
+ '勉' => '勉',
+ '勤' => '勤',
+ '勺' => '勺',
+ '包' => '包',
+ '匆' => '匆',
+ '北' => '北',
+ '卉' => '卉',
+ '卑' => '卑',
+ '博' => '博',
+ '即' => '即',
+ '卽' => '卽',
+ '卿' => '卿',
+ '卿' => '卿',
+ '卿' => '卿',
+ '𠨬' => '𠨬',
+ '灰' => '灰',
+ '及' => '及',
+ '叟' => '叟',
+ '𠭣' => '𠭣',
+ '叫' => '叫',
+ '叱' => '叱',
+ '吆' => '吆',
+ '咞' => '咞',
+ '吸' => '吸',
+ '呈' => '呈',
+ '周' => '周',
+ '咢' => '咢',
+ '哶' => '哶',
+ '唐' => '唐',
+ '啓' => '啓',
+ '啣' => '啣',
+ '善' => '善',
+ '善' => '善',
+ '喙' => '喙',
+ '喫' => '喫',
+ '喳' => '喳',
+ '嗂' => '嗂',
+ '圖' => '圖',
+ '嘆' => '嘆',
+ '圗' => '圗',
+ '噑' => '噑',
+ '噴' => '噴',
+ '切' => '切',
+ '壮' => '壮',
+ '城' => '城',
+ '埴' => '埴',
+ '堍' => '堍',
+ '型' => '型',
+ '堲' => '堲',
+ '報' => '報',
+ '墬' => '墬',
+ '𡓤' => '𡓤',
+ '売' => '売',
+ '壷' => '壷',
+ '夆' => '夆',
+ '多' => '多',
+ '夢' => '夢',
+ '奢' => '奢',
+ '𡚨' => '𡚨',
+ '𡛪' => '𡛪',
+ '姬' => '姬',
+ '娛' => '娛',
+ '娧' => '娧',
+ '姘' => '姘',
+ '婦' => '婦',
+ '㛮' => '㛮',
+ '㛼' => '㛼',
+ '嬈' => '嬈',
+ '嬾' => '嬾',
+ '嬾' => '嬾',
+ '𡧈' => '𡧈',
+ '寃' => '寃',
+ '寘' => '寘',
+ '寧' => '寧',
+ '寳' => '寳',
+ '𡬘' => '𡬘',
+ '寿' => '寿',
+ '将' => '将',
+ '当' => '当',
+ '尢' => '尢',
+ '㞁' => '㞁',
+ '屠' => '屠',
+ '屮' => '屮',
+ '峀' => '峀',
+ '岍' => '岍',
+ '𡷤' => '𡷤',
+ '嵃' => '嵃',
+ '𡷦' => '𡷦',
+ '嵮' => '嵮',
+ '嵫' => '嵫',
+ '嵼' => '嵼',
+ '巡' => '巡',
+ '巢' => '巢',
+ '㠯' => '㠯',
+ '巽' => '巽',
+ '帨' => '帨',
+ '帽' => '帽',
+ '幩' => '幩',
+ '㡢' => '㡢',
+ '𢆃' => '𢆃',
+ '㡼' => '㡼',
+ '庰' => '庰',
+ '庳' => '庳',
+ '庶' => '庶',
+ '廊' => '廊',
+ '𪎒' => '𪎒',
+ '廾' => '廾',
+ '𢌱' => '𢌱',
+ '𢌱' => '𢌱',
+ '舁' => '舁',
+ '弢' => '弢',
+ '弢' => '弢',
+ '㣇' => '㣇',
+ '𣊸' => '𣊸',
+ '𦇚' => '𦇚',
+ '形' => '形',
+ '彫' => '彫',
+ '㣣' => '㣣',
+ '徚' => '徚',
+ '忍' => '忍',
+ '志' => '志',
+ '忹' => '忹',
+ '悁' => '悁',
+ '㤺' => '㤺',
+ '㤜' => '㤜',
+ '悔' => '悔',
+ '𢛔' => '𢛔',
+ '惇' => '惇',
+ '慈' => '慈',
+ '慌' => '慌',
+ '慎' => '慎',
+ '慌' => '慌',
+ '慺' => '慺',
+ '憎' => '憎',
+ '憲' => '憲',
+ '憤' => '憤',
+ '憯' => '憯',
+ '懞' => '懞',
+ '懲' => '懲',
+ '懶' => '懶',
+ '成' => '成',
+ '戛' => '戛',
+ '扝' => '扝',
+ '抱' => '抱',
+ '拔' => '拔',
+ '捐' => '捐',
+ '𢬌' => '𢬌',
+ '挽' => '挽',
+ '拼' => '拼',
+ '捨' => '捨',
+ '掃' => '掃',
+ '揤' => '揤',
+ '𢯱' => '𢯱',
+ '搢' => '搢',
+ '揅' => '揅',
+ '掩' => '掩',
+ '㨮' => '㨮',
+ '摩' => '摩',
+ '摾' => '摾',
+ '撝' => '撝',
+ '摷' => '摷',
+ '㩬' => '㩬',
+ '敏' => '敏',
+ '敬' => '敬',
+ '𣀊' => '𣀊',
+ '旣' => '旣',
+ '書' => '書',
+ '晉' => '晉',
+ '㬙' => '㬙',
+ '暑' => '暑',
+ '㬈' => '㬈',
+ '㫤' => '㫤',
+ '冒' => '冒',
+ '冕' => '冕',
+ '最' => '最',
+ '暜' => '暜',
+ '肭' => '肭',
+ '䏙' => '䏙',
+ '朗' => '朗',
+ '望' => '望',
+ '朡' => '朡',
+ '杞' => '杞',
+ '杓' => '杓',
+ '𣏃' => '𣏃',
+ '㭉' => '㭉',
+ '柺' => '柺',
+ '枅' => '枅',
+ '桒' => '桒',
+ '梅' => '梅',
+ '𣑭' => '𣑭',
+ '梎' => '梎',
+ '栟' => '栟',
+ '椔' => '椔',
+ '㮝' => '㮝',
+ '楂' => '楂',
+ '榣' => '榣',
+ '槪' => '槪',
+ '檨' => '檨',
+ '𣚣' => '𣚣',
+ '櫛' => '櫛',
+ '㰘' => '㰘',
+ '次' => '次',
+ '𣢧' => '𣢧',
+ '歔' => '歔',
+ '㱎' => '㱎',
+ '歲' => '歲',
+ '殟' => '殟',
+ '殺' => '殺',
+ '殻' => '殻',
+ '𣪍' => '𣪍',
+ '𡴋' => '𡴋',
+ '𣫺' => '𣫺',
+ '汎' => '汎',
+ '𣲼' => '𣲼',
+ '沿' => '沿',
+ '泍' => '泍',
+ '汧' => '汧',
+ '洖' => '洖',
+ '派' => '派',
+ '海' => '海',
+ '流' => '流',
+ '浩' => '浩',
+ '浸' => '浸',
+ '涅' => '涅',
+ '𣴞' => '𣴞',
+ '洴' => '洴',
+ '港' => '港',
+ '湮' => '湮',
+ '㴳' => '㴳',
+ '滋' => '滋',
+ '滇' => '滇',
+ '𣻑' => '𣻑',
+ '淹' => '淹',
+ '潮' => '潮',
+ '𣽞' => '𣽞',
+ '𣾎' => '𣾎',
+ '濆' => '濆',
+ '瀹' => '瀹',
+ '瀞' => '瀞',
+ '瀛' => '瀛',
+ '㶖' => '㶖',
+ '灊' => '灊',
+ '災' => '災',
+ '灷' => '灷',
+ '炭' => '炭',
+ '𠔥' => '𠔥',
+ '煅' => '煅',
+ '𤉣' => '𤉣',
+ '熜' => '熜',
+ '𤎫' => '𤎫',
+ '爨' => '爨',
+ '爵' => '爵',
+ '牐' => '牐',
+ '𤘈' => '𤘈',
+ '犀' => '犀',
+ '犕' => '犕',
+ '𤜵' => '𤜵',
+ '𤠔' => '𤠔',
+ '獺' => '獺',
+ '王' => '王',
+ '㺬' => '㺬',
+ '玥' => '玥',
+ '㺸' => '㺸',
+ '㺸' => '㺸',
+ '瑇' => '瑇',
+ '瑜' => '瑜',
+ '瑱' => '瑱',
+ '璅' => '璅',
+ '瓊' => '瓊',
+ '㼛' => '㼛',
+ '甤' => '甤',
+ '𤰶' => '𤰶',
+ '甾' => '甾',
+ '𤲒' => '𤲒',
+ '異' => '異',
+ '𢆟' => '𢆟',
+ '瘐' => '瘐',
+ '𤾡' => '𤾡',
+ '𤾸' => '𤾸',
+ '𥁄' => '𥁄',
+ '㿼' => '㿼',
+ '䀈' => '䀈',
+ '直' => '直',
+ '𥃳' => '𥃳',
+ '𥃲' => '𥃲',
+ '𥄙' => '𥄙',
+ '𥄳' => '𥄳',
+ '眞' => '眞',
+ '真' => '真',
+ '真' => '真',
+ '睊' => '睊',
+ '䀹' => '䀹',
+ '瞋' => '瞋',
+ '䁆' => '䁆',
+ '䂖' => '䂖',
+ '𥐝' => '𥐝',
+ '硎' => '硎',
+ '碌' => '碌',
+ '磌' => '磌',
+ '䃣' => '䃣',
+ '𥘦' => '𥘦',
+ '祖' => '祖',
+ '𥚚' => '𥚚',
+ '𥛅' => '𥛅',
+ '福' => '福',
+ '秫' => '秫',
+ '䄯' => '䄯',
+ '穀' => '穀',
+ '穊' => '穊',
+ '穏' => '穏',
+ '𥥼' => '𥥼',
+ '𥪧' => '𥪧',
+ '𥪧' => '𥪧',
+ '竮' => '竮',
+ '䈂' => '䈂',
+ '𥮫' => '𥮫',
+ '篆' => '篆',
+ '築' => '築',
+ '䈧' => '䈧',
+ '𥲀' => '𥲀',
+ '糒' => '糒',
+ '䊠' => '䊠',
+ '糨' => '糨',
+ '糣' => '糣',
+ '紀' => '紀',
+ '𥾆' => '𥾆',
+ '絣' => '絣',
+ '䌁' => '䌁',
+ '緇' => '緇',
+ '縂' => '縂',
+ '繅' => '繅',
+ '䌴' => '䌴',
+ '𦈨' => '𦈨',
+ '𦉇' => '𦉇',
+ '䍙' => '䍙',
+ '𦋙' => '𦋙',
+ '罺' => '罺',
+ '𦌾' => '𦌾',
+ '羕' => '羕',
+ '翺' => '翺',
+ '者' => '者',
+ '𦓚' => '𦓚',
+ '𦔣' => '𦔣',
+ '聠' => '聠',
+ '𦖨' => '𦖨',
+ '聰' => '聰',
+ '𣍟' => '𣍟',
+ '䏕' => '䏕',
+ '育' => '育',
+ '脃' => '脃',
+ '䐋' => '䐋',
+ '脾' => '脾',
+ '媵' => '媵',
+ '𦞧' => '𦞧',
+ '𦞵' => '𦞵',
+ '𣎓' => '𣎓',
+ '𣎜' => '𣎜',
+ '舁' => '舁',
+ '舄' => '舄',
+ '辞' => '辞',
+ '䑫' => '䑫',
+ '芑' => '芑',
+ '芋' => '芋',
+ '芝' => '芝',
+ '劳' => '劳',
+ '花' => '花',
+ '芳' => '芳',
+ '芽' => '芽',
+ '苦' => '苦',
+ '𦬼' => '𦬼',
+ '若' => '若',
+ '茝' => '茝',
+ '荣' => '荣',
+ '莭' => '莭',
+ '茣' => '茣',
+ '莽' => '莽',
+ '菧' => '菧',
+ '著' => '著',
+ '荓' => '荓',
+ '菊' => '菊',
+ '菌' => '菌',
+ '菜' => '菜',
+ '𦰶' => '𦰶',
+ '𦵫' => '𦵫',
+ '𦳕' => '𦳕',
+ '䔫' => '䔫',
+ '蓱' => '蓱',
+ '蓳' => '蓳',
+ '蔖' => '蔖',
+ '𧏊' => '𧏊',
+ '蕤' => '蕤',
+ '𦼬' => '𦼬',
+ '䕝' => '䕝',
+ '䕡' => '䕡',
+ '𦾱' => '𦾱',
+ '𧃒' => '𧃒',
+ '䕫' => '䕫',
+ '虐' => '虐',
+ '虜' => '虜',
+ '虧' => '虧',
+ '虩' => '虩',
+ '蚩' => '蚩',
+ '蚈' => '蚈',
+ '蜎' => '蜎',
+ '蛢' => '蛢',
+ '蝹' => '蝹',
+ '蜨' => '蜨',
+ '蝫' => '蝫',
+ '螆' => '螆',
+ '䗗' => '䗗',
+ '蟡' => '蟡',
+ '蠁' => '蠁',
+ '䗹' => '䗹',
+ '衠' => '衠',
+ '衣' => '衣',
+ '𧙧' => '𧙧',
+ '裗' => '裗',
+ '裞' => '裞',
+ '䘵' => '䘵',
+ '裺' => '裺',
+ '㒻' => '㒻',
+ '𧢮' => '𧢮',
+ '𧥦' => '𧥦',
+ '䚾' => '䚾',
+ '䛇' => '䛇',
+ '誠' => '誠',
+ '諭' => '諭',
+ '變' => '變',
+ '豕' => '豕',
+ '𧲨' => '𧲨',
+ '貫' => '貫',
+ '賁' => '賁',
+ '贛' => '贛',
+ '起' => '起',
+ '𧼯' => '𧼯',
+ '𠠄' => '𠠄',
+ '跋' => '跋',
+ '趼' => '趼',
+ '跰' => '跰',
+ '𠣞' => '𠣞',
+ '軔' => '軔',
+ '輸' => '輸',
+ '𨗒' => '𨗒',
+ '𨗭' => '𨗭',
+ '邔' => '邔',
+ '郱' => '郱',
+ '鄑' => '鄑',
+ '𨜮' => '𨜮',
+ '鄛' => '鄛',
+ '鈸' => '鈸',
+ '鋗' => '鋗',
+ '鋘' => '鋘',
+ '鉼' => '鉼',
+ '鏹' => '鏹',
+ '鐕' => '鐕',
+ '𨯺' => '𨯺',
+ '開' => '開',
+ '䦕' => '䦕',
+ '閷' => '閷',
+ '𨵷' => '𨵷',
+ '䧦' => '䧦',
+ '雃' => '雃',
+ '嶲' => '嶲',
+ '霣' => '霣',
+ '𩅅' => '𩅅',
+ '𩈚' => '𩈚',
+ '䩮' => '䩮',
+ '䩶' => '䩶',
+ '韠' => '韠',
+ '𩐊' => '𩐊',
+ '䪲' => '䪲',
+ '𩒖' => '𩒖',
+ '頋' => '頋',
+ '頋' => '頋',
+ '頩' => '頩',
+ '𩖶' => '𩖶',
+ '飢' => '飢',
+ '䬳' => '䬳',
+ '餩' => '餩',
+ '馧' => '馧',
+ '駂' => '駂',
+ '駾' => '駾',
+ '䯎' => '䯎',
+ '𩬰' => '𩬰',
+ '鬒' => '鬒',
+ '鱀' => '鱀',
+ '鳽' => '鳽',
+ '䳎' => '䳎',
+ '䳭' => '䳭',
+ '鵧' => '鵧',
+ '𪃎' => '𪃎',
+ '䳸' => '䳸',
+ '𪄅' => '𪄅',
+ '𪈎' => '𪈎',
+ '𪊑' => '𪊑',
+ '麻' => '麻',
+ '䵖' => '䵖',
+ '黹' => '黹',
+ '黾' => '黾',
+ '鼅' => '鼅',
+ '鼏' => '鼏',
+ '鼖' => '鼖',
+ '鼻' => '鼻',
+ '𪘀' => '𪘀',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php
new file mode 100644
index 0000000..ec90f36
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php
@@ -0,0 +1,876 @@
+<?php
+
+return array (
+ '̀' => 230,
+ '́' => 230,
+ '̂' => 230,
+ '̃' => 230,
+ '̄' => 230,
+ '̅' => 230,
+ '̆' => 230,
+ '̇' => 230,
+ '̈' => 230,
+ '̉' => 230,
+ '̊' => 230,
+ '̋' => 230,
+ '̌' => 230,
+ '̍' => 230,
+ '̎' => 230,
+ '̏' => 230,
+ '̐' => 230,
+ '̑' => 230,
+ '̒' => 230,
+ '̓' => 230,
+ '̔' => 230,
+ '̕' => 232,
+ '̖' => 220,
+ '̗' => 220,
+ '̘' => 220,
+ '̙' => 220,
+ '̚' => 232,
+ '̛' => 216,
+ '̜' => 220,
+ '̝' => 220,
+ '̞' => 220,
+ '̟' => 220,
+ '̠' => 220,
+ '̡' => 202,
+ '̢' => 202,
+ '̣' => 220,
+ '̤' => 220,
+ '̥' => 220,
+ '̦' => 220,
+ '̧' => 202,
+ '̨' => 202,
+ '̩' => 220,
+ '̪' => 220,
+ '̫' => 220,
+ '̬' => 220,
+ '̭' => 220,
+ '̮' => 220,
+ '̯' => 220,
+ '̰' => 220,
+ '̱' => 220,
+ '̲' => 220,
+ '̳' => 220,
+ '̴' => 1,
+ '̵' => 1,
+ '̶' => 1,
+ '̷' => 1,
+ '̸' => 1,
+ '̹' => 220,
+ '̺' => 220,
+ '̻' => 220,
+ '̼' => 220,
+ '̽' => 230,
+ '̾' => 230,
+ '̿' => 230,
+ '̀' => 230,
+ '́' => 230,
+ '͂' => 230,
+ '̓' => 230,
+ '̈́' => 230,
+ 'ͅ' => 240,
+ '͆' => 230,
+ '͇' => 220,
+ '͈' => 220,
+ '͉' => 220,
+ '͊' => 230,
+ '͋' => 230,
+ '͌' => 230,
+ '͍' => 220,
+ '͎' => 220,
+ '͐' => 230,
+ '͑' => 230,
+ '͒' => 230,
+ '͓' => 220,
+ '͔' => 220,
+ '͕' => 220,
+ '͖' => 220,
+ '͗' => 230,
+ '͘' => 232,
+ '͙' => 220,
+ '͚' => 220,
+ '͛' => 230,
+ '͜' => 233,
+ '͝' => 234,
+ '͞' => 234,
+ '͟' => 233,
+ '͠' => 234,
+ '͡' => 234,
+ '͢' => 233,
+ 'ͣ' => 230,
+ 'ͤ' => 230,
+ 'ͥ' => 230,
+ 'ͦ' => 230,
+ 'ͧ' => 230,
+ 'ͨ' => 230,
+ 'ͩ' => 230,
+ 'ͪ' => 230,
+ 'ͫ' => 230,
+ 'ͬ' => 230,
+ 'ͭ' => 230,
+ 'ͮ' => 230,
+ 'ͯ' => 230,
+ '҃' => 230,
+ '҄' => 230,
+ '҅' => 230,
+ '҆' => 230,
+ '҇' => 230,
+ '֑' => 220,
+ '֒' => 230,
+ '֓' => 230,
+ '֔' => 230,
+ '֕' => 230,
+ '֖' => 220,
+ '֗' => 230,
+ '֘' => 230,
+ '֙' => 230,
+ '֚' => 222,
+ '֛' => 220,
+ '֜' => 230,
+ '֝' => 230,
+ '֞' => 230,
+ '֟' => 230,
+ '֠' => 230,
+ '֡' => 230,
+ '֢' => 220,
+ '֣' => 220,
+ '֤' => 220,
+ '֥' => 220,
+ '֦' => 220,
+ '֧' => 220,
+ '֨' => 230,
+ '֩' => 230,
+ '֪' => 220,
+ '֫' => 230,
+ '֬' => 230,
+ '֭' => 222,
+ '֮' => 228,
+ '֯' => 230,
+ 'ְ' => 10,
+ 'ֱ' => 11,
+ 'ֲ' => 12,
+ 'ֳ' => 13,
+ 'ִ' => 14,
+ 'ֵ' => 15,
+ 'ֶ' => 16,
+ 'ַ' => 17,
+ 'ָ' => 18,
+ 'ֹ' => 19,
+ 'ֺ' => 19,
+ 'ֻ' => 20,
+ 'ּ' => 21,
+ 'ֽ' => 22,
+ 'ֿ' => 23,
+ 'ׁ' => 24,
+ 'ׂ' => 25,
+ 'ׄ' => 230,
+ 'ׅ' => 220,
+ 'ׇ' => 18,
+ 'ؐ' => 230,
+ 'ؑ' => 230,
+ 'ؒ' => 230,
+ 'ؓ' => 230,
+ 'ؔ' => 230,
+ 'ؕ' => 230,
+ 'ؖ' => 230,
+ 'ؗ' => 230,
+ 'ؘ' => 30,
+ 'ؙ' => 31,
+ 'ؚ' => 32,
+ 'ً' => 27,
+ 'ٌ' => 28,
+ 'ٍ' => 29,
+ 'َ' => 30,
+ 'ُ' => 31,
+ 'ِ' => 32,
+ 'ّ' => 33,
+ 'ْ' => 34,
+ 'ٓ' => 230,
+ 'ٔ' => 230,
+ 'ٕ' => 220,
+ 'ٖ' => 220,
+ 'ٗ' => 230,
+ '٘' => 230,
+ 'ٙ' => 230,
+ 'ٚ' => 230,
+ 'ٛ' => 230,
+ 'ٜ' => 220,
+ 'ٝ' => 230,
+ 'ٞ' => 230,
+ 'ٟ' => 220,
+ 'ٰ' => 35,
+ 'ۖ' => 230,
+ 'ۗ' => 230,
+ 'ۘ' => 230,
+ 'ۙ' => 230,
+ 'ۚ' => 230,
+ 'ۛ' => 230,
+ 'ۜ' => 230,
+ '۟' => 230,
+ '۠' => 230,
+ 'ۡ' => 230,
+ 'ۢ' => 230,
+ 'ۣ' => 220,
+ 'ۤ' => 230,
+ 'ۧ' => 230,
+ 'ۨ' => 230,
+ '۪' => 220,
+ '۫' => 230,
+ '۬' => 230,
+ 'ۭ' => 220,
+ 'ܑ' => 36,
+ 'ܰ' => 230,
+ 'ܱ' => 220,
+ 'ܲ' => 230,
+ 'ܳ' => 230,
+ 'ܴ' => 220,
+ 'ܵ' => 230,
+ 'ܶ' => 230,
+ 'ܷ' => 220,
+ 'ܸ' => 220,
+ 'ܹ' => 220,
+ 'ܺ' => 230,
+ 'ܻ' => 220,
+ 'ܼ' => 220,
+ 'ܽ' => 230,
+ 'ܾ' => 220,
+ 'ܿ' => 230,
+ '݀' => 230,
+ '݁' => 230,
+ '݂' => 220,
+ '݃' => 230,
+ '݄' => 220,
+ '݅' => 230,
+ '݆' => 220,
+ '݇' => 230,
+ '݈' => 220,
+ '݉' => 230,
+ '݊' => 230,
+ '߫' => 230,
+ '߬' => 230,
+ '߭' => 230,
+ '߮' => 230,
+ '߯' => 230,
+ '߰' => 230,
+ '߱' => 230,
+ '߲' => 220,
+ '߳' => 230,
+ '߽' => 220,
+ 'ࠖ' => 230,
+ 'ࠗ' => 230,
+ '࠘' => 230,
+ '࠙' => 230,
+ 'ࠛ' => 230,
+ 'ࠜ' => 230,
+ 'ࠝ' => 230,
+ 'ࠞ' => 230,
+ 'ࠟ' => 230,
+ 'ࠠ' => 230,
+ 'ࠡ' => 230,
+ 'ࠢ' => 230,
+ 'ࠣ' => 230,
+ 'ࠥ' => 230,
+ 'ࠦ' => 230,
+ 'ࠧ' => 230,
+ 'ࠩ' => 230,
+ 'ࠪ' => 230,
+ 'ࠫ' => 230,
+ 'ࠬ' => 230,
+ '࠭' => 230,
+ '࡙' => 220,
+ '࡚' => 220,
+ '࡛' => 220,
+ '࣓' => 220,
+ 'ࣔ' => 230,
+ 'ࣕ' => 230,
+ 'ࣖ' => 230,
+ 'ࣗ' => 230,
+ 'ࣘ' => 230,
+ 'ࣙ' => 230,
+ 'ࣚ' => 230,
+ 'ࣛ' => 230,
+ 'ࣜ' => 230,
+ 'ࣝ' => 230,
+ 'ࣞ' => 230,
+ 'ࣟ' => 230,
+ '࣠' => 230,
+ '࣡' => 230,
+ 'ࣣ' => 220,
+ 'ࣤ' => 230,
+ 'ࣥ' => 230,
+ 'ࣦ' => 220,
+ 'ࣧ' => 230,
+ 'ࣨ' => 230,
+ 'ࣩ' => 220,
+ '࣪' => 230,
+ '࣫' => 230,
+ '࣬' => 230,
+ '࣭' => 220,
+ '࣮' => 220,
+ '࣯' => 220,
+ 'ࣰ' => 27,
+ 'ࣱ' => 28,
+ 'ࣲ' => 29,
+ 'ࣳ' => 230,
+ 'ࣴ' => 230,
+ 'ࣵ' => 230,
+ 'ࣶ' => 220,
+ 'ࣷ' => 230,
+ 'ࣸ' => 230,
+ 'ࣹ' => 220,
+ 'ࣺ' => 220,
+ 'ࣻ' => 230,
+ 'ࣼ' => 230,
+ 'ࣽ' => 230,
+ 'ࣾ' => 230,
+ 'ࣿ' => 230,
+ '़' => 7,
+ '्' => 9,
+ '॑' => 230,
+ '॒' => 220,
+ '॓' => 230,
+ '॔' => 230,
+ '়' => 7,
+ '্' => 9,
+ '৾' => 230,
+ '਼' => 7,
+ '੍' => 9,
+ '઼' => 7,
+ '્' => 9,
+ '଼' => 7,
+ '୍' => 9,
+ '்' => 9,
+ '్' => 9,
+ 'ౕ' => 84,
+ 'ౖ' => 91,
+ '಼' => 7,
+ '್' => 9,
+ '഻' => 9,
+ '഼' => 9,
+ '്' => 9,
+ '්' => 9,
+ 'ุ' => 103,
+ 'ู' => 103,
+ 'ฺ' => 9,
+ '่' => 107,
+ '้' => 107,
+ '๊' => 107,
+ '๋' => 107,
+ 'ຸ' => 118,
+ 'ູ' => 118,
+ '຺' => 9,
+ '່' => 122,
+ '້' => 122,
+ '໊' => 122,
+ '໋' => 122,
+ '༘' => 220,
+ '༙' => 220,
+ '༵' => 220,
+ '༷' => 220,
+ '༹' => 216,
+ 'ཱ' => 129,
+ 'ི' => 130,
+ 'ུ' => 132,
+ 'ེ' => 130,
+ 'ཻ' => 130,
+ 'ོ' => 130,
+ 'ཽ' => 130,
+ 'ྀ' => 130,
+ 'ྂ' => 230,
+ 'ྃ' => 230,
+ '྄' => 9,
+ '྆' => 230,
+ '྇' => 230,
+ '࿆' => 220,
+ '့' => 7,
+ '္' => 9,
+ '်' => 9,
+ 'ႍ' => 220,
+ '፝' => 230,
+ '፞' => 230,
+ '፟' => 230,
+ '᜔' => 9,
+ '᜴' => 9,
+ '្' => 9,
+ '៝' => 230,
+ 'ᢩ' => 228,
+ '᤹' => 222,
+ '᤺' => 230,
+ '᤻' => 220,
+ 'ᨗ' => 230,
+ 'ᨘ' => 220,
+ '᩠' => 9,
+ '᩵' => 230,
+ '᩶' => 230,
+ '᩷' => 230,
+ '᩸' => 230,
+ '᩹' => 230,
+ '᩺' => 230,
+ '᩻' => 230,
+ '᩼' => 230,
+ '᩿' => 220,
+ '᪰' => 230,
+ '᪱' => 230,
+ '᪲' => 230,
+ '᪳' => 230,
+ '᪴' => 230,
+ '᪵' => 220,
+ '᪶' => 220,
+ '᪷' => 220,
+ '᪸' => 220,
+ '᪹' => 220,
+ '᪺' => 220,
+ '᪻' => 230,
+ '᪼' => 230,
+ '᪽' => 220,
+ 'ᪿ' => 220,
+ 'ᫀ' => 220,
+ '᬴' => 7,
+ '᭄' => 9,
+ '᭫' => 230,
+ '᭬' => 220,
+ '᭭' => 230,
+ '᭮' => 230,
+ '᭯' => 230,
+ '᭰' => 230,
+ '᭱' => 230,
+ '᭲' => 230,
+ '᭳' => 230,
+ '᮪' => 9,
+ '᮫' => 9,
+ '᯦' => 7,
+ '᯲' => 9,
+ '᯳' => 9,
+ '᰷' => 7,
+ '᳐' => 230,
+ '᳑' => 230,
+ '᳒' => 230,
+ '᳔' => 1,
+ '᳕' => 220,
+ '᳖' => 220,
+ '᳗' => 220,
+ '᳘' => 220,
+ '᳙' => 220,
+ '᳚' => 230,
+ '᳛' => 230,
+ '᳜' => 220,
+ '᳝' => 220,
+ '᳞' => 220,
+ '᳟' => 220,
+ '᳠' => 230,
+ '᳢' => 1,
+ '᳣' => 1,
+ '᳤' => 1,
+ '᳥' => 1,
+ '᳦' => 1,
+ '᳧' => 1,
+ '᳨' => 1,
+ '᳭' => 220,
+ '᳴' => 230,
+ '᳸' => 230,
+ '᳹' => 230,
+ '᷀' => 230,
+ '᷁' => 230,
+ '᷂' => 220,
+ '᷃' => 230,
+ '᷄' => 230,
+ '᷅' => 230,
+ '᷆' => 230,
+ '᷇' => 230,
+ '᷈' => 230,
+ '᷉' => 230,
+ '᷊' => 220,
+ '᷋' => 230,
+ '᷌' => 230,
+ '᷍' => 234,
+ '᷎' => 214,
+ '᷏' => 220,
+ '᷐' => 202,
+ '᷑' => 230,
+ '᷒' => 230,
+ 'ᷓ' => 230,
+ 'ᷔ' => 230,
+ 'ᷕ' => 230,
+ 'ᷖ' => 230,
+ 'ᷗ' => 230,
+ 'ᷘ' => 230,
+ 'ᷙ' => 230,
+ 'ᷚ' => 230,
+ 'ᷛ' => 230,
+ 'ᷜ' => 230,
+ 'ᷝ' => 230,
+ 'ᷞ' => 230,
+ 'ᷟ' => 230,
+ 'ᷠ' => 230,
+ 'ᷡ' => 230,
+ 'ᷢ' => 230,
+ 'ᷣ' => 230,
+ 'ᷤ' => 230,
+ 'ᷥ' => 230,
+ 'ᷦ' => 230,
+ 'ᷧ' => 230,
+ 'ᷨ' => 230,
+ 'ᷩ' => 230,
+ 'ᷪ' => 230,
+ 'ᷫ' => 230,
+ 'ᷬ' => 230,
+ 'ᷭ' => 230,
+ 'ᷮ' => 230,
+ 'ᷯ' => 230,
+ 'ᷰ' => 230,
+ 'ᷱ' => 230,
+ 'ᷲ' => 230,
+ 'ᷳ' => 230,
+ 'ᷴ' => 230,
+ '᷵' => 230,
+ '᷶' => 232,
+ '᷷' => 228,
+ '᷸' => 228,
+ '᷹' => 220,
+ '᷻' => 230,
+ '᷼' => 233,
+ '᷽' => 220,
+ '᷾' => 230,
+ '᷿' => 220,
+ '⃐' => 230,
+ '⃑' => 230,
+ '⃒' => 1,
+ '⃓' => 1,
+ '⃔' => 230,
+ '⃕' => 230,
+ '⃖' => 230,
+ '⃗' => 230,
+ '⃘' => 1,
+ '⃙' => 1,
+ '⃚' => 1,
+ '⃛' => 230,
+ '⃜' => 230,
+ '⃡' => 230,
+ '⃥' => 1,
+ '⃦' => 1,
+ '⃧' => 230,
+ '⃨' => 220,
+ '⃩' => 230,
+ '⃪' => 1,
+ '⃫' => 1,
+ '⃬' => 220,
+ '⃭' => 220,
+ '⃮' => 220,
+ '⃯' => 220,
+ '⃰' => 230,
+ '⳯' => 230,
+ '⳰' => 230,
+ '⳱' => 230,
+ '⵿' => 9,
+ 'ⷠ' => 230,
+ 'ⷡ' => 230,
+ 'ⷢ' => 230,
+ 'ⷣ' => 230,
+ 'ⷤ' => 230,
+ 'ⷥ' => 230,
+ 'ⷦ' => 230,
+ 'ⷧ' => 230,
+ 'ⷨ' => 230,
+ 'ⷩ' => 230,
+ 'ⷪ' => 230,
+ 'ⷫ' => 230,
+ 'ⷬ' => 230,
+ 'ⷭ' => 230,
+ 'ⷮ' => 230,
+ 'ⷯ' => 230,
+ 'ⷰ' => 230,
+ 'ⷱ' => 230,
+ 'ⷲ' => 230,
+ 'ⷳ' => 230,
+ 'ⷴ' => 230,
+ 'ⷵ' => 230,
+ 'ⷶ' => 230,
+ 'ⷷ' => 230,
+ 'ⷸ' => 230,
+ 'ⷹ' => 230,
+ 'ⷺ' => 230,
+ 'ⷻ' => 230,
+ 'ⷼ' => 230,
+ 'ⷽ' => 230,
+ 'ⷾ' => 230,
+ 'ⷿ' => 230,
+ '〪' => 218,
+ '〫' => 228,
+ '〬' => 232,
+ '〭' => 222,
+ '〮' => 224,
+ '〯' => 224,
+ '゙' => 8,
+ '゚' => 8,
+ '꙯' => 230,
+ 'ꙴ' => 230,
+ 'ꙵ' => 230,
+ 'ꙶ' => 230,
+ 'ꙷ' => 230,
+ 'ꙸ' => 230,
+ 'ꙹ' => 230,
+ 'ꙺ' => 230,
+ 'ꙻ' => 230,
+ '꙼' => 230,
+ '꙽' => 230,
+ 'ꚞ' => 230,
+ 'ꚟ' => 230,
+ '꛰' => 230,
+ '꛱' => 230,
+ '꠆' => 9,
+ '꠬' => 9,
+ '꣄' => 9,
+ '꣠' => 230,
+ '꣡' => 230,
+ '꣢' => 230,
+ '꣣' => 230,
+ '꣤' => 230,
+ '꣥' => 230,
+ '꣦' => 230,
+ '꣧' => 230,
+ '꣨' => 230,
+ '꣩' => 230,
+ '꣪' => 230,
+ '꣫' => 230,
+ '꣬' => 230,
+ '꣭' => 230,
+ '꣮' => 230,
+ '꣯' => 230,
+ '꣰' => 230,
+ '꣱' => 230,
+ '꤫' => 220,
+ '꤬' => 220,
+ '꤭' => 220,
+ '꥓' => 9,
+ '꦳' => 7,
+ '꧀' => 9,
+ 'ꪰ' => 230,
+ 'ꪲ' => 230,
+ 'ꪳ' => 230,
+ 'ꪴ' => 220,
+ 'ꪷ' => 230,
+ 'ꪸ' => 230,
+ 'ꪾ' => 230,
+ '꪿' => 230,
+ '꫁' => 230,
+ '꫶' => 9,
+ '꯭' => 9,
+ 'ﬞ' => 26,
+ '︠' => 230,
+ '︡' => 230,
+ '︢' => 230,
+ '︣' => 230,
+ '︤' => 230,
+ '︥' => 230,
+ '︦' => 230,
+ '︧' => 220,
+ '︨' => 220,
+ '︩' => 220,
+ '︪' => 220,
+ '︫' => 220,
+ '︬' => 220,
+ '︭' => 220,
+ '︮' => 230,
+ '︯' => 230,
+ '𐇽' => 220,
+ '𐋠' => 220,
+ '𐍶' => 230,
+ '𐍷' => 230,
+ '𐍸' => 230,
+ '𐍹' => 230,
+ '𐍺' => 230,
+ '𐨍' => 220,
+ '𐨏' => 230,
+ '𐨸' => 230,
+ '𐨹' => 1,
+ '𐨺' => 220,
+ '𐨿' => 9,
+ '𐫥' => 230,
+ '𐫦' => 220,
+ '𐴤' => 230,
+ '𐴥' => 230,
+ '𐴦' => 230,
+ '𐴧' => 230,
+ '𐺫' => 230,
+ '𐺬' => 230,
+ '𐽆' => 220,
+ '𐽇' => 220,
+ '𐽈' => 230,
+ '𐽉' => 230,
+ '𐽊' => 230,
+ '𐽋' => 220,
+ '𐽌' => 230,
+ '𐽍' => 220,
+ '𐽎' => 220,
+ '𐽏' => 220,
+ '𐽐' => 220,
+ '𑁆' => 9,
+ '𑁿' => 9,
+ '𑂹' => 9,
+ '𑂺' => 7,
+ '𑄀' => 230,
+ '𑄁' => 230,
+ '𑄂' => 230,
+ '𑄳' => 9,
+ '𑄴' => 9,
+ '𑅳' => 7,
+ '𑇀' => 9,
+ '𑇊' => 7,
+ '𑈵' => 9,
+ '𑈶' => 7,
+ '𑋩' => 7,
+ '𑋪' => 9,
+ '𑌻' => 7,
+ '𑌼' => 7,
+ '𑍍' => 9,
+ '𑍦' => 230,
+ '𑍧' => 230,
+ '𑍨' => 230,
+ '𑍩' => 230,
+ '𑍪' => 230,
+ '𑍫' => 230,
+ '𑍬' => 230,
+ '𑍰' => 230,
+ '𑍱' => 230,
+ '𑍲' => 230,
+ '𑍳' => 230,
+ '𑍴' => 230,
+ '𑑂' => 9,
+ '𑑆' => 7,
+ '𑑞' => 230,
+ '𑓂' => 9,
+ '𑓃' => 7,
+ '𑖿' => 9,
+ '𑗀' => 7,
+ '𑘿' => 9,
+ '𑚶' => 9,
+ '𑚷' => 7,
+ '𑜫' => 9,
+ '𑠹' => 9,
+ '𑠺' => 7,
+ '𑤽' => 9,
+ '𑤾' => 9,
+ '𑥃' => 7,
+ '𑧠' => 9,
+ '𑨴' => 9,
+ '𑩇' => 9,
+ '𑪙' => 9,
+ '𑰿' => 9,
+ '𑵂' => 7,
+ '𑵄' => 9,
+ '𑵅' => 9,
+ '𑶗' => 9,
+ '𖫰' => 1,
+ '𖫱' => 1,
+ '𖫲' => 1,
+ '𖫳' => 1,
+ '𖫴' => 1,
+ '𖬰' => 230,
+ '𖬱' => 230,
+ '𖬲' => 230,
+ '𖬳' => 230,
+ '𖬴' => 230,
+ '𖬵' => 230,
+ '𖬶' => 230,
+ '𖿰' => 6,
+ '𖿱' => 6,
+ '𛲞' => 1,
+ '𝅥' => 216,
+ '𝅦' => 216,
+ '𝅧' => 1,
+ '𝅨' => 1,
+ '𝅩' => 1,
+ '𝅭' => 226,
+ '𝅮' => 216,
+ '𝅯' => 216,
+ '𝅰' => 216,
+ '𝅱' => 216,
+ '𝅲' => 216,
+ '𝅻' => 220,
+ '𝅼' => 220,
+ '𝅽' => 220,
+ '𝅾' => 220,
+ '𝅿' => 220,
+ '𝆀' => 220,
+ '𝆁' => 220,
+ '𝆂' => 220,
+ '𝆅' => 230,
+ '𝆆' => 230,
+ '𝆇' => 230,
+ '𝆈' => 230,
+ '𝆉' => 230,
+ '𝆊' => 220,
+ '𝆋' => 220,
+ '𝆪' => 230,
+ '𝆫' => 230,
+ '𝆬' => 230,
+ '𝆭' => 230,
+ '𝉂' => 230,
+ '𝉃' => 230,
+ '𝉄' => 230,
+ '𞀀' => 230,
+ '𞀁' => 230,
+ '𞀂' => 230,
+ '𞀃' => 230,
+ '𞀄' => 230,
+ '𞀅' => 230,
+ '𞀆' => 230,
+ '𞀈' => 230,
+ '𞀉' => 230,
+ '𞀊' => 230,
+ '𞀋' => 230,
+ '𞀌' => 230,
+ '𞀍' => 230,
+ '𞀎' => 230,
+ '𞀏' => 230,
+ '𞀐' => 230,
+ '𞀑' => 230,
+ '𞀒' => 230,
+ '𞀓' => 230,
+ '𞀔' => 230,
+ '𞀕' => 230,
+ '𞀖' => 230,
+ '𞀗' => 230,
+ '𞀘' => 230,
+ '𞀛' => 230,
+ '𞀜' => 230,
+ '𞀝' => 230,
+ '𞀞' => 230,
+ '𞀟' => 230,
+ '𞀠' => 230,
+ '𞀡' => 230,
+ '𞀣' => 230,
+ '𞀤' => 230,
+ '𞀦' => 230,
+ '𞀧' => 230,
+ '𞀨' => 230,
+ '𞀩' => 230,
+ '𞀪' => 230,
+ '𞄰' => 230,
+ '𞄱' => 230,
+ '𞄲' => 230,
+ '𞄳' => 230,
+ '𞄴' => 230,
+ '𞄵' => 230,
+ '𞄶' => 230,
+ '𞋬' => 230,
+ '𞋭' => 230,
+ '𞋮' => 230,
+ '𞋯' => 230,
+ '𞣐' => 220,
+ '𞣑' => 220,
+ '𞣒' => 220,
+ '𞣓' => 220,
+ '𞣔' => 220,
+ '𞣕' => 220,
+ '𞣖' => 220,
+ '𞥄' => 230,
+ '𞥅' => 230,
+ '𞥆' => 230,
+ '𞥇' => 230,
+ '𞥈' => 230,
+ '𞥉' => 230,
+ '𞥊' => 7,
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php
new file mode 100644
index 0000000..1574902
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php
@@ -0,0 +1,3695 @@
+<?php
+
+return array (
+ ' ' => ' ',
+ '¨' => ' ̈',
+ 'ª' => 'a',
+ '¯' => ' ̄',
+ '²' => '2',
+ '³' => '3',
+ '´' => ' ́',
+ 'µ' => 'μ',
+ '¸' => ' ̧',
+ '¹' => '1',
+ 'º' => 'o',
+ '¼' => '1⁄4',
+ '½' => '1⁄2',
+ '¾' => '3⁄4',
+ 'IJ' => 'IJ',
+ 'ij' => 'ij',
+ 'Ŀ' => 'L·',
+ 'ŀ' => 'l·',
+ 'ʼn' => 'ʼn',
+ 'ſ' => 's',
+ 'DŽ' => 'DŽ',
+ 'Dž' => 'Dž',
+ 'dž' => 'dž',
+ 'LJ' => 'LJ',
+ 'Lj' => 'Lj',
+ 'lj' => 'lj',
+ 'NJ' => 'NJ',
+ 'Nj' => 'Nj',
+ 'nj' => 'nj',
+ 'DZ' => 'DZ',
+ 'Dz' => 'Dz',
+ 'dz' => 'dz',
+ 'ʰ' => 'h',
+ 'ʱ' => 'ɦ',
+ 'ʲ' => 'j',
+ 'ʳ' => 'r',
+ 'ʴ' => 'ɹ',
+ 'ʵ' => 'ɻ',
+ 'ʶ' => 'ʁ',
+ 'ʷ' => 'w',
+ 'ʸ' => 'y',
+ '˘' => ' ̆',
+ '˙' => ' ̇',
+ '˚' => ' ̊',
+ '˛' => ' ̨',
+ '˜' => ' ̃',
+ '˝' => ' ̋',
+ 'ˠ' => 'ɣ',
+ 'ˡ' => 'l',
+ 'ˢ' => 's',
+ 'ˣ' => 'x',
+ 'ˤ' => 'ʕ',
+ 'ͺ' => ' ͅ',
+ '΄' => ' ́',
+ '΅' => ' ̈́',
+ 'ϐ' => 'β',
+ 'ϑ' => 'θ',
+ 'ϒ' => 'Υ',
+ 'ϓ' => 'Ύ',
+ 'ϔ' => 'Ϋ',
+ 'ϕ' => 'φ',
+ 'ϖ' => 'π',
+ 'ϰ' => 'κ',
+ 'ϱ' => 'ρ',
+ 'ϲ' => 'ς',
+ 'ϴ' => 'Θ',
+ 'ϵ' => 'ε',
+ 'Ϲ' => 'Σ',
+ 'և' => 'եւ',
+ 'ٵ' => 'اٴ',
+ 'ٶ' => 'وٴ',
+ 'ٷ' => 'ۇٴ',
+ 'ٸ' => 'يٴ',
+ 'ำ' => 'ํา',
+ 'ຳ' => 'ໍາ',
+ 'ໜ' => 'ຫນ',
+ 'ໝ' => 'ຫມ',
+ '༌' => '་',
+ 'ཷ' => 'ྲཱྀ',
+ 'ཹ' => 'ླཱྀ',
+ 'ჼ' => 'ნ',
+ 'ᴬ' => 'A',
+ 'ᴭ' => 'Æ',
+ 'ᴮ' => 'B',
+ 'ᴰ' => 'D',
+ 'ᴱ' => 'E',
+ 'ᴲ' => 'Ǝ',
+ 'ᴳ' => 'G',
+ 'ᴴ' => 'H',
+ 'ᴵ' => 'I',
+ 'ᴶ' => 'J',
+ 'ᴷ' => 'K',
+ 'ᴸ' => 'L',
+ 'ᴹ' => 'M',
+ 'ᴺ' => 'N',
+ 'ᴼ' => 'O',
+ 'ᴽ' => 'Ȣ',
+ 'ᴾ' => 'P',
+ 'ᴿ' => 'R',
+ 'ᵀ' => 'T',
+ 'ᵁ' => 'U',
+ 'ᵂ' => 'W',
+ 'ᵃ' => 'a',
+ 'ᵄ' => 'ɐ',
+ 'ᵅ' => 'ɑ',
+ 'ᵆ' => 'ᴂ',
+ 'ᵇ' => 'b',
+ 'ᵈ' => 'd',
+ 'ᵉ' => 'e',
+ 'ᵊ' => 'ə',
+ 'ᵋ' => 'ɛ',
+ 'ᵌ' => 'ɜ',
+ 'ᵍ' => 'g',
+ 'ᵏ' => 'k',
+ 'ᵐ' => 'm',
+ 'ᵑ' => 'ŋ',
+ 'ᵒ' => 'o',
+ 'ᵓ' => 'ɔ',
+ 'ᵔ' => 'ᴖ',
+ 'ᵕ' => 'ᴗ',
+ 'ᵖ' => 'p',
+ 'ᵗ' => 't',
+ 'ᵘ' => 'u',
+ 'ᵙ' => 'ᴝ',
+ 'ᵚ' => 'ɯ',
+ 'ᵛ' => 'v',
+ 'ᵜ' => 'ᴥ',
+ 'ᵝ' => 'β',
+ 'ᵞ' => 'γ',
+ 'ᵟ' => 'δ',
+ 'ᵠ' => 'φ',
+ 'ᵡ' => 'χ',
+ 'ᵢ' => 'i',
+ 'ᵣ' => 'r',
+ 'ᵤ' => 'u',
+ 'ᵥ' => 'v',
+ 'ᵦ' => 'β',
+ 'ᵧ' => 'γ',
+ 'ᵨ' => 'ρ',
+ 'ᵩ' => 'φ',
+ 'ᵪ' => 'χ',
+ 'ᵸ' => 'н',
+ 'ᶛ' => 'ɒ',
+ 'ᶜ' => 'c',
+ 'ᶝ' => 'ɕ',
+ 'ᶞ' => 'ð',
+ 'ᶟ' => 'ɜ',
+ 'ᶠ' => 'f',
+ 'ᶡ' => 'ɟ',
+ 'ᶢ' => 'ɡ',
+ 'ᶣ' => 'ɥ',
+ 'ᶤ' => 'ɨ',
+ 'ᶥ' => 'ɩ',
+ 'ᶦ' => 'ɪ',
+ 'ᶧ' => 'ᵻ',
+ 'ᶨ' => 'ʝ',
+ 'ᶩ' => 'ɭ',
+ 'ᶪ' => 'ᶅ',
+ 'ᶫ' => 'ʟ',
+ 'ᶬ' => 'ɱ',
+ 'ᶭ' => 'ɰ',
+ 'ᶮ' => 'ɲ',
+ 'ᶯ' => 'ɳ',
+ 'ᶰ' => 'ɴ',
+ 'ᶱ' => 'ɵ',
+ 'ᶲ' => 'ɸ',
+ 'ᶳ' => 'ʂ',
+ 'ᶴ' => 'ʃ',
+ 'ᶵ' => 'ƫ',
+ 'ᶶ' => 'ʉ',
+ 'ᶷ' => 'ʊ',
+ 'ᶸ' => 'ᴜ',
+ 'ᶹ' => 'ʋ',
+ 'ᶺ' => 'ʌ',
+ 'ᶻ' => 'z',
+ 'ᶼ' => 'ʐ',
+ 'ᶽ' => 'ʑ',
+ 'ᶾ' => 'ʒ',
+ 'ᶿ' => 'θ',
+ 'ẚ' => 'aʾ',
+ 'ẛ' => 'ṡ',
+ '᾽' => ' ̓',
+ '᾿' => ' ̓',
+ '῀' => ' ͂',
+ '῁' => ' ̈͂',
+ '῍' => ' ̓̀',
+ '῎' => ' ̓́',
+ '῏' => ' ̓͂',
+ '῝' => ' ̔̀',
+ '῞' => ' ̔́',
+ '῟' => ' ̔͂',
+ '῭' => ' ̈̀',
+ '΅' => ' ̈́',
+ '´' => ' ́',
+ '῾' => ' ̔',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ '‑' => '‐',
+ '‗' => ' ̳',
+ '․' => '.',
+ '‥' => '..',
+ '…' => '...',
+ ' ' => ' ',
+ '″' => '′′',
+ '‴' => '′′′',
+ '‶' => '‵‵',
+ '‷' => '‵‵‵',
+ '‼' => '!!',
+ '‾' => ' ̅',
+ '⁇' => '??',
+ '⁈' => '?!',
+ '⁉' => '!?',
+ '⁗' => '′′′′',
+ ' ' => ' ',
+ '⁰' => '0',
+ 'ⁱ' => 'i',
+ '⁴' => '4',
+ '⁵' => '5',
+ '⁶' => '6',
+ '⁷' => '7',
+ '⁸' => '8',
+ '⁹' => '9',
+ '⁺' => '+',
+ '⁻' => '−',
+ '⁼' => '=',
+ '⁽' => '(',
+ '⁾' => ')',
+ 'ⁿ' => 'n',
+ '₀' => '0',
+ '₁' => '1',
+ '₂' => '2',
+ '₃' => '3',
+ '₄' => '4',
+ '₅' => '5',
+ '₆' => '6',
+ '₇' => '7',
+ '₈' => '8',
+ '₉' => '9',
+ '₊' => '+',
+ '₋' => '−',
+ '₌' => '=',
+ '₍' => '(',
+ '₎' => ')',
+ 'ₐ' => 'a',
+ 'ₑ' => 'e',
+ 'ₒ' => 'o',
+ 'ₓ' => 'x',
+ 'ₔ' => 'ə',
+ 'ₕ' => 'h',
+ 'ₖ' => 'k',
+ 'ₗ' => 'l',
+ 'ₘ' => 'm',
+ 'ₙ' => 'n',
+ 'ₚ' => 'p',
+ 'ₛ' => 's',
+ 'ₜ' => 't',
+ '₨' => 'Rs',
+ '℀' => 'a/c',
+ '℁' => 'a/s',
+ 'ℂ' => 'C',
+ '℃' => '°C',
+ '℅' => 'c/o',
+ '℆' => 'c/u',
+ 'ℇ' => 'Ɛ',
+ '℉' => '°F',
+ 'ℊ' => 'g',
+ 'ℋ' => 'H',
+ 'ℌ' => 'H',
+ 'ℍ' => 'H',
+ 'ℎ' => 'h',
+ 'ℏ' => 'ħ',
+ 'ℐ' => 'I',
+ 'ℑ' => 'I',
+ 'ℒ' => 'L',
+ 'ℓ' => 'l',
+ 'ℕ' => 'N',
+ '№' => 'No',
+ 'ℙ' => 'P',
+ 'ℚ' => 'Q',
+ 'ℛ' => 'R',
+ 'ℜ' => 'R',
+ 'ℝ' => 'R',
+ '℠' => 'SM',
+ '℡' => 'TEL',
+ '™' => 'TM',
+ 'ℤ' => 'Z',
+ 'ℨ' => 'Z',
+ 'ℬ' => 'B',
+ 'ℭ' => 'C',
+ 'ℯ' => 'e',
+ 'ℰ' => 'E',
+ 'ℱ' => 'F',
+ 'ℳ' => 'M',
+ 'ℴ' => 'o',
+ 'ℵ' => 'א',
+ 'ℶ' => 'ב',
+ 'ℷ' => 'ג',
+ 'ℸ' => 'ד',
+ 'ℹ' => 'i',
+ '℻' => 'FAX',
+ 'ℼ' => 'π',
+ 'ℽ' => 'γ',
+ 'ℾ' => 'Γ',
+ 'ℿ' => 'Π',
+ '⅀' => '∑',
+ 'ⅅ' => 'D',
+ 'ⅆ' => 'd',
+ 'ⅇ' => 'e',
+ 'ⅈ' => 'i',
+ 'ⅉ' => 'j',
+ '⅐' => '1⁄7',
+ '⅑' => '1⁄9',
+ '⅒' => '1⁄10',
+ '⅓' => '1⁄3',
+ '⅔' => '2⁄3',
+ '⅕' => '1⁄5',
+ '⅖' => '2⁄5',
+ '⅗' => '3⁄5',
+ '⅘' => '4⁄5',
+ '⅙' => '1⁄6',
+ '⅚' => '5⁄6',
+ '⅛' => '1⁄8',
+ '⅜' => '3⁄8',
+ '⅝' => '5⁄8',
+ '⅞' => '7⁄8',
+ '⅟' => '1⁄',
+ 'Ⅰ' => 'I',
+ 'Ⅱ' => 'II',
+ 'Ⅲ' => 'III',
+ 'Ⅳ' => 'IV',
+ 'Ⅴ' => 'V',
+ 'Ⅵ' => 'VI',
+ 'Ⅶ' => 'VII',
+ 'Ⅷ' => 'VIII',
+ 'Ⅸ' => 'IX',
+ 'Ⅹ' => 'X',
+ 'Ⅺ' => 'XI',
+ 'Ⅻ' => 'XII',
+ 'Ⅼ' => 'L',
+ 'Ⅽ' => 'C',
+ 'Ⅾ' => 'D',
+ 'Ⅿ' => 'M',
+ 'ⅰ' => 'i',
+ 'ⅱ' => 'ii',
+ 'ⅲ' => 'iii',
+ 'ⅳ' => 'iv',
+ 'ⅴ' => 'v',
+ 'ⅵ' => 'vi',
+ 'ⅶ' => 'vii',
+ 'ⅷ' => 'viii',
+ 'ⅸ' => 'ix',
+ 'ⅹ' => 'x',
+ 'ⅺ' => 'xi',
+ 'ⅻ' => 'xii',
+ 'ⅼ' => 'l',
+ 'ⅽ' => 'c',
+ 'ⅾ' => 'd',
+ 'ⅿ' => 'm',
+ '↉' => '0⁄3',
+ '∬' => '∫∫',
+ '∭' => '∫∫∫',
+ '∯' => '∮∮',
+ '∰' => '∮∮∮',
+ '①' => '1',
+ '②' => '2',
+ '③' => '3',
+ '④' => '4',
+ '⑤' => '5',
+ '⑥' => '6',
+ '⑦' => '7',
+ '⑧' => '8',
+ '⑨' => '9',
+ '⑩' => '10',
+ '⑪' => '11',
+ '⑫' => '12',
+ '⑬' => '13',
+ '⑭' => '14',
+ '⑮' => '15',
+ '⑯' => '16',
+ '⑰' => '17',
+ '⑱' => '18',
+ '⑲' => '19',
+ '⑳' => '20',
+ '⑴' => '(1)',
+ '⑵' => '(2)',
+ '⑶' => '(3)',
+ '⑷' => '(4)',
+ '⑸' => '(5)',
+ '⑹' => '(6)',
+ '⑺' => '(7)',
+ '⑻' => '(8)',
+ '⑼' => '(9)',
+ '⑽' => '(10)',
+ '⑾' => '(11)',
+ '⑿' => '(12)',
+ '⒀' => '(13)',
+ '⒁' => '(14)',
+ '⒂' => '(15)',
+ '⒃' => '(16)',
+ '⒄' => '(17)',
+ '⒅' => '(18)',
+ '⒆' => '(19)',
+ '⒇' => '(20)',
+ '⒈' => '1.',
+ '⒉' => '2.',
+ '⒊' => '3.',
+ '⒋' => '4.',
+ '⒌' => '5.',
+ '⒍' => '6.',
+ '⒎' => '7.',
+ '⒏' => '8.',
+ '⒐' => '9.',
+ '⒑' => '10.',
+ '⒒' => '11.',
+ '⒓' => '12.',
+ '⒔' => '13.',
+ '⒕' => '14.',
+ '⒖' => '15.',
+ '⒗' => '16.',
+ '⒘' => '17.',
+ '⒙' => '18.',
+ '⒚' => '19.',
+ '⒛' => '20.',
+ '⒜' => '(a)',
+ '⒝' => '(b)',
+ '⒞' => '(c)',
+ '⒟' => '(d)',
+ '⒠' => '(e)',
+ '⒡' => '(f)',
+ '⒢' => '(g)',
+ '⒣' => '(h)',
+ '⒤' => '(i)',
+ '⒥' => '(j)',
+ '⒦' => '(k)',
+ '⒧' => '(l)',
+ '⒨' => '(m)',
+ '⒩' => '(n)',
+ '⒪' => '(o)',
+ '⒫' => '(p)',
+ '⒬' => '(q)',
+ '⒭' => '(r)',
+ '⒮' => '(s)',
+ '⒯' => '(t)',
+ '⒰' => '(u)',
+ '⒱' => '(v)',
+ '⒲' => '(w)',
+ '⒳' => '(x)',
+ '⒴' => '(y)',
+ '⒵' => '(z)',
+ 'Ⓐ' => 'A',
+ 'Ⓑ' => 'B',
+ 'Ⓒ' => 'C',
+ 'Ⓓ' => 'D',
+ 'Ⓔ' => 'E',
+ 'Ⓕ' => 'F',
+ 'Ⓖ' => 'G',
+ 'Ⓗ' => 'H',
+ 'Ⓘ' => 'I',
+ 'Ⓙ' => 'J',
+ 'Ⓚ' => 'K',
+ 'Ⓛ' => 'L',
+ 'Ⓜ' => 'M',
+ 'Ⓝ' => 'N',
+ 'Ⓞ' => 'O',
+ 'Ⓟ' => 'P',
+ 'Ⓠ' => 'Q',
+ 'Ⓡ' => 'R',
+ 'Ⓢ' => 'S',
+ 'Ⓣ' => 'T',
+ 'Ⓤ' => 'U',
+ 'Ⓥ' => 'V',
+ 'Ⓦ' => 'W',
+ 'Ⓧ' => 'X',
+ 'Ⓨ' => 'Y',
+ 'Ⓩ' => 'Z',
+ 'ⓐ' => 'a',
+ 'ⓑ' => 'b',
+ 'ⓒ' => 'c',
+ 'ⓓ' => 'd',
+ 'ⓔ' => 'e',
+ 'ⓕ' => 'f',
+ 'ⓖ' => 'g',
+ 'ⓗ' => 'h',
+ 'ⓘ' => 'i',
+ 'ⓙ' => 'j',
+ 'ⓚ' => 'k',
+ 'ⓛ' => 'l',
+ 'ⓜ' => 'm',
+ 'ⓝ' => 'n',
+ 'ⓞ' => 'o',
+ 'ⓟ' => 'p',
+ 'ⓠ' => 'q',
+ 'ⓡ' => 'r',
+ 'ⓢ' => 's',
+ 'ⓣ' => 't',
+ 'ⓤ' => 'u',
+ 'ⓥ' => 'v',
+ 'ⓦ' => 'w',
+ 'ⓧ' => 'x',
+ 'ⓨ' => 'y',
+ 'ⓩ' => 'z',
+ '⓪' => '0',
+ '⨌' => '∫∫∫∫',
+ '⩴' => '::=',
+ '⩵' => '==',
+ '⩶' => '===',
+ 'ⱼ' => 'j',
+ 'ⱽ' => 'V',
+ 'ⵯ' => 'ⵡ',
+ '⺟' => '母',
+ '⻳' => '龟',
+ '⼀' => '一',
+ '⼁' => '丨',
+ '⼂' => '丶',
+ '⼃' => '丿',
+ '⼄' => '乙',
+ '⼅' => '亅',
+ '⼆' => '二',
+ '⼇' => '亠',
+ '⼈' => '人',
+ '⼉' => '儿',
+ '⼊' => '入',
+ '⼋' => '八',
+ '⼌' => '冂',
+ '⼍' => '冖',
+ '⼎' => '冫',
+ '⼏' => '几',
+ '⼐' => '凵',
+ '⼑' => '刀',
+ '⼒' => '力',
+ '⼓' => '勹',
+ '⼔' => '匕',
+ '⼕' => '匚',
+ '⼖' => '匸',
+ '⼗' => '十',
+ '⼘' => '卜',
+ '⼙' => '卩',
+ '⼚' => '厂',
+ '⼛' => '厶',
+ '⼜' => '又',
+ '⼝' => '口',
+ '⼞' => '囗',
+ '⼟' => '土',
+ '⼠' => '士',
+ '⼡' => '夂',
+ '⼢' => '夊',
+ '⼣' => '夕',
+ '⼤' => '大',
+ '⼥' => '女',
+ '⼦' => '子',
+ '⼧' => '宀',
+ '⼨' => '寸',
+ '⼩' => '小',
+ '⼪' => '尢',
+ '⼫' => '尸',
+ '⼬' => '屮',
+ '⼭' => '山',
+ '⼮' => '巛',
+ '⼯' => '工',
+ '⼰' => '己',
+ '⼱' => '巾',
+ '⼲' => '干',
+ '⼳' => '幺',
+ '⼴' => '广',
+ '⼵' => '廴',
+ '⼶' => '廾',
+ '⼷' => '弋',
+ '⼸' => '弓',
+ '⼹' => '彐',
+ '⼺' => '彡',
+ '⼻' => '彳',
+ '⼼' => '心',
+ '⼽' => '戈',
+ '⼾' => '戶',
+ '⼿' => '手',
+ '⽀' => '支',
+ '⽁' => '攴',
+ '⽂' => '文',
+ '⽃' => '斗',
+ '⽄' => '斤',
+ '⽅' => '方',
+ '⽆' => '无',
+ '⽇' => '日',
+ '⽈' => '曰',
+ '⽉' => '月',
+ '⽊' => '木',
+ '⽋' => '欠',
+ '⽌' => '止',
+ '⽍' => '歹',
+ '⽎' => '殳',
+ '⽏' => '毋',
+ '⽐' => '比',
+ '⽑' => '毛',
+ '⽒' => '氏',
+ '⽓' => '气',
+ '⽔' => '水',
+ '⽕' => '火',
+ '⽖' => '爪',
+ '⽗' => '父',
+ '⽘' => '爻',
+ '⽙' => '爿',
+ '⽚' => '片',
+ '⽛' => '牙',
+ '⽜' => '牛',
+ '⽝' => '犬',
+ '⽞' => '玄',
+ '⽟' => '玉',
+ '⽠' => '瓜',
+ '⽡' => '瓦',
+ '⽢' => '甘',
+ '⽣' => '生',
+ '⽤' => '用',
+ '⽥' => '田',
+ '⽦' => '疋',
+ '⽧' => '疒',
+ '⽨' => '癶',
+ '⽩' => '白',
+ '⽪' => '皮',
+ '⽫' => '皿',
+ '⽬' => '目',
+ '⽭' => '矛',
+ '⽮' => '矢',
+ '⽯' => '石',
+ '⽰' => '示',
+ '⽱' => '禸',
+ '⽲' => '禾',
+ '⽳' => '穴',
+ '⽴' => '立',
+ '⽵' => '竹',
+ '⽶' => '米',
+ '⽷' => '糸',
+ '⽸' => '缶',
+ '⽹' => '网',
+ '⽺' => '羊',
+ '⽻' => '羽',
+ '⽼' => '老',
+ '⽽' => '而',
+ '⽾' => '耒',
+ '⽿' => '耳',
+ '⾀' => '聿',
+ '⾁' => '肉',
+ '⾂' => '臣',
+ '⾃' => '自',
+ '⾄' => '至',
+ '⾅' => '臼',
+ '⾆' => '舌',
+ '⾇' => '舛',
+ '⾈' => '舟',
+ '⾉' => '艮',
+ '⾊' => '色',
+ '⾋' => '艸',
+ '⾌' => '虍',
+ '⾍' => '虫',
+ '⾎' => '血',
+ '⾏' => '行',
+ '⾐' => '衣',
+ '⾑' => '襾',
+ '⾒' => '見',
+ '⾓' => '角',
+ '⾔' => '言',
+ '⾕' => '谷',
+ '⾖' => '豆',
+ '⾗' => '豕',
+ '⾘' => '豸',
+ '⾙' => '貝',
+ '⾚' => '赤',
+ '⾛' => '走',
+ '⾜' => '足',
+ '⾝' => '身',
+ '⾞' => '車',
+ '⾟' => '辛',
+ '⾠' => '辰',
+ '⾡' => '辵',
+ '⾢' => '邑',
+ '⾣' => '酉',
+ '⾤' => '釆',
+ '⾥' => '里',
+ '⾦' => '金',
+ '⾧' => '長',
+ '⾨' => '門',
+ '⾩' => '阜',
+ '⾪' => '隶',
+ '⾫' => '隹',
+ '⾬' => '雨',
+ '⾭' => '靑',
+ '⾮' => '非',
+ '⾯' => '面',
+ '⾰' => '革',
+ '⾱' => '韋',
+ '⾲' => '韭',
+ '⾳' => '音',
+ '⾴' => '頁',
+ '⾵' => '風',
+ '⾶' => '飛',
+ '⾷' => '食',
+ '⾸' => '首',
+ '⾹' => '香',
+ '⾺' => '馬',
+ '⾻' => '骨',
+ '⾼' => '高',
+ '⾽' => '髟',
+ '⾾' => '鬥',
+ '⾿' => '鬯',
+ '⿀' => '鬲',
+ '⿁' => '鬼',
+ '⿂' => '魚',
+ '⿃' => '鳥',
+ '⿄' => '鹵',
+ '⿅' => '鹿',
+ '⿆' => '麥',
+ '⿇' => '麻',
+ '⿈' => '黃',
+ '⿉' => '黍',
+ '⿊' => '黑',
+ '⿋' => '黹',
+ '⿌' => '黽',
+ '⿍' => '鼎',
+ '⿎' => '鼓',
+ '⿏' => '鼠',
+ '⿐' => '鼻',
+ '⿑' => '齊',
+ '⿒' => '齒',
+ '⿓' => '龍',
+ '⿔' => '龜',
+ '⿕' => '龠',
+ ' ' => ' ',
+ '〶' => '〒',
+ '〸' => '十',
+ '〹' => '卄',
+ '〺' => '卅',
+ '゛' => ' ゙',
+ '゜' => ' ゚',
+ 'ゟ' => 'より',
+ 'ヿ' => 'コト',
+ 'ㄱ' => 'ᄀ',
+ 'ㄲ' => 'ᄁ',
+ 'ㄳ' => 'ᆪ',
+ 'ㄴ' => 'ᄂ',
+ 'ㄵ' => 'ᆬ',
+ 'ㄶ' => 'ᆭ',
+ 'ㄷ' => 'ᄃ',
+ 'ㄸ' => 'ᄄ',
+ 'ㄹ' => 'ᄅ',
+ 'ㄺ' => 'ᆰ',
+ 'ㄻ' => 'ᆱ',
+ 'ㄼ' => 'ᆲ',
+ 'ㄽ' => 'ᆳ',
+ 'ㄾ' => 'ᆴ',
+ 'ㄿ' => 'ᆵ',
+ 'ㅀ' => 'ᄚ',
+ 'ㅁ' => 'ᄆ',
+ 'ㅂ' => 'ᄇ',
+ 'ㅃ' => 'ᄈ',
+ 'ㅄ' => 'ᄡ',
+ 'ㅅ' => 'ᄉ',
+ 'ㅆ' => 'ᄊ',
+ 'ㅇ' => 'ᄋ',
+ 'ㅈ' => 'ᄌ',
+ 'ㅉ' => 'ᄍ',
+ 'ㅊ' => 'ᄎ',
+ 'ㅋ' => 'ᄏ',
+ 'ㅌ' => 'ᄐ',
+ 'ㅍ' => 'ᄑ',
+ 'ㅎ' => 'ᄒ',
+ 'ㅏ' => 'ᅡ',
+ 'ㅐ' => 'ᅢ',
+ 'ㅑ' => 'ᅣ',
+ 'ㅒ' => 'ᅤ',
+ 'ㅓ' => 'ᅥ',
+ 'ㅔ' => 'ᅦ',
+ 'ㅕ' => 'ᅧ',
+ 'ㅖ' => 'ᅨ',
+ 'ㅗ' => 'ᅩ',
+ 'ㅘ' => 'ᅪ',
+ 'ㅙ' => 'ᅫ',
+ 'ㅚ' => 'ᅬ',
+ 'ㅛ' => 'ᅭ',
+ 'ㅜ' => 'ᅮ',
+ 'ㅝ' => 'ᅯ',
+ 'ㅞ' => 'ᅰ',
+ 'ㅟ' => 'ᅱ',
+ 'ㅠ' => 'ᅲ',
+ 'ㅡ' => 'ᅳ',
+ 'ㅢ' => 'ᅴ',
+ 'ㅣ' => 'ᅵ',
+ 'ㅤ' => 'ᅠ',
+ 'ㅥ' => 'ᄔ',
+ 'ㅦ' => 'ᄕ',
+ 'ㅧ' => 'ᇇ',
+ 'ㅨ' => 'ᇈ',
+ 'ㅩ' => 'ᇌ',
+ 'ㅪ' => 'ᇎ',
+ 'ㅫ' => 'ᇓ',
+ 'ㅬ' => 'ᇗ',
+ 'ㅭ' => 'ᇙ',
+ 'ㅮ' => 'ᄜ',
+ 'ㅯ' => 'ᇝ',
+ 'ㅰ' => 'ᇟ',
+ 'ㅱ' => 'ᄝ',
+ 'ㅲ' => 'ᄞ',
+ 'ㅳ' => 'ᄠ',
+ 'ㅴ' => 'ᄢ',
+ 'ㅵ' => 'ᄣ',
+ 'ㅶ' => 'ᄧ',
+ 'ㅷ' => 'ᄩ',
+ 'ㅸ' => 'ᄫ',
+ 'ㅹ' => 'ᄬ',
+ 'ㅺ' => 'ᄭ',
+ 'ㅻ' => 'ᄮ',
+ 'ㅼ' => 'ᄯ',
+ 'ㅽ' => 'ᄲ',
+ 'ㅾ' => 'ᄶ',
+ 'ㅿ' => 'ᅀ',
+ 'ㆀ' => 'ᅇ',
+ 'ㆁ' => 'ᅌ',
+ 'ㆂ' => 'ᇱ',
+ 'ㆃ' => 'ᇲ',
+ 'ㆄ' => 'ᅗ',
+ 'ㆅ' => 'ᅘ',
+ 'ㆆ' => 'ᅙ',
+ 'ㆇ' => 'ᆄ',
+ 'ㆈ' => 'ᆅ',
+ 'ㆉ' => 'ᆈ',
+ 'ㆊ' => 'ᆑ',
+ 'ㆋ' => 'ᆒ',
+ 'ㆌ' => 'ᆔ',
+ 'ㆍ' => 'ᆞ',
+ 'ㆎ' => 'ᆡ',
+ '㆒' => '一',
+ '㆓' => '二',
+ '㆔' => '三',
+ '㆕' => '四',
+ '㆖' => '上',
+ '㆗' => '中',
+ '㆘' => '下',
+ '㆙' => '甲',
+ '㆚' => '乙',
+ '㆛' => '丙',
+ '㆜' => '丁',
+ '㆝' => '天',
+ '㆞' => '地',
+ '㆟' => '人',
+ '㈀' => '(ᄀ)',
+ '㈁' => '(ᄂ)',
+ '㈂' => '(ᄃ)',
+ '㈃' => '(ᄅ)',
+ '㈄' => '(ᄆ)',
+ '㈅' => '(ᄇ)',
+ '㈆' => '(ᄉ)',
+ '㈇' => '(ᄋ)',
+ '㈈' => '(ᄌ)',
+ '㈉' => '(ᄎ)',
+ '㈊' => '(ᄏ)',
+ '㈋' => '(ᄐ)',
+ '㈌' => '(ᄑ)',
+ '㈍' => '(ᄒ)',
+ '㈎' => '(가)',
+ '㈏' => '(나)',
+ '㈐' => '(다)',
+ '㈑' => '(라)',
+ '㈒' => '(마)',
+ '㈓' => '(바)',
+ '㈔' => '(사)',
+ '㈕' => '(아)',
+ '㈖' => '(자)',
+ '㈗' => '(차)',
+ '㈘' => '(카)',
+ '㈙' => '(타)',
+ '㈚' => '(파)',
+ '㈛' => '(하)',
+ '㈜' => '(주)',
+ '㈝' => '(오전)',
+ '㈞' => '(오후)',
+ '㈠' => '(一)',
+ '㈡' => '(二)',
+ '㈢' => '(三)',
+ '㈣' => '(四)',
+ '㈤' => '(五)',
+ '㈥' => '(六)',
+ '㈦' => '(七)',
+ '㈧' => '(八)',
+ '㈨' => '(九)',
+ '㈩' => '(十)',
+ '㈪' => '(月)',
+ '㈫' => '(火)',
+ '㈬' => '(水)',
+ '㈭' => '(木)',
+ '㈮' => '(金)',
+ '㈯' => '(土)',
+ '㈰' => '(日)',
+ '㈱' => '(株)',
+ '㈲' => '(有)',
+ '㈳' => '(社)',
+ '㈴' => '(名)',
+ '㈵' => '(特)',
+ '㈶' => '(財)',
+ '㈷' => '(祝)',
+ '㈸' => '(労)',
+ '㈹' => '(代)',
+ '㈺' => '(呼)',
+ '㈻' => '(学)',
+ '㈼' => '(監)',
+ '㈽' => '(企)',
+ '㈾' => '(資)',
+ '㈿' => '(協)',
+ '㉀' => '(祭)',
+ '㉁' => '(休)',
+ '㉂' => '(自)',
+ '㉃' => '(至)',
+ '㉄' => '問',
+ '㉅' => '幼',
+ '㉆' => '文',
+ '㉇' => '箏',
+ '㉐' => 'PTE',
+ '㉑' => '21',
+ '㉒' => '22',
+ '㉓' => '23',
+ '㉔' => '24',
+ '㉕' => '25',
+ '㉖' => '26',
+ '㉗' => '27',
+ '㉘' => '28',
+ '㉙' => '29',
+ '㉚' => '30',
+ '㉛' => '31',
+ '㉜' => '32',
+ '㉝' => '33',
+ '㉞' => '34',
+ '㉟' => '35',
+ '㉠' => 'ᄀ',
+ '㉡' => 'ᄂ',
+ '㉢' => 'ᄃ',
+ '㉣' => 'ᄅ',
+ '㉤' => 'ᄆ',
+ '㉥' => 'ᄇ',
+ '㉦' => 'ᄉ',
+ '㉧' => 'ᄋ',
+ '㉨' => 'ᄌ',
+ '㉩' => 'ᄎ',
+ '㉪' => 'ᄏ',
+ '㉫' => 'ᄐ',
+ '㉬' => 'ᄑ',
+ '㉭' => 'ᄒ',
+ '㉮' => '가',
+ '㉯' => '나',
+ '㉰' => '다',
+ '㉱' => '라',
+ '㉲' => '마',
+ '㉳' => '바',
+ '㉴' => '사',
+ '㉵' => '아',
+ '㉶' => '자',
+ '㉷' => '차',
+ '㉸' => '카',
+ '㉹' => '타',
+ '㉺' => '파',
+ '㉻' => '하',
+ '㉼' => '참고',
+ '㉽' => '주의',
+ '㉾' => '우',
+ '㊀' => '一',
+ '㊁' => '二',
+ '㊂' => '三',
+ '㊃' => '四',
+ '㊄' => '五',
+ '㊅' => '六',
+ '㊆' => '七',
+ '㊇' => '八',
+ '㊈' => '九',
+ '㊉' => '十',
+ '㊊' => '月',
+ '㊋' => '火',
+ '㊌' => '水',
+ '㊍' => '木',
+ '㊎' => '金',
+ '㊏' => '土',
+ '㊐' => '日',
+ '㊑' => '株',
+ '㊒' => '有',
+ '㊓' => '社',
+ '㊔' => '名',
+ '㊕' => '特',
+ '㊖' => '財',
+ '㊗' => '祝',
+ '㊘' => '労',
+ '㊙' => '秘',
+ '㊚' => '男',
+ '㊛' => '女',
+ '㊜' => '適',
+ '㊝' => '優',
+ '㊞' => '印',
+ '㊟' => '注',
+ '㊠' => '項',
+ '㊡' => '休',
+ '㊢' => '写',
+ '㊣' => '正',
+ '㊤' => '上',
+ '㊥' => '中',
+ '㊦' => '下',
+ '㊧' => '左',
+ '㊨' => '右',
+ '㊩' => '医',
+ '㊪' => '宗',
+ '㊫' => '学',
+ '㊬' => '監',
+ '㊭' => '企',
+ '㊮' => '資',
+ '㊯' => '協',
+ '㊰' => '夜',
+ '㊱' => '36',
+ '㊲' => '37',
+ '㊳' => '38',
+ '㊴' => '39',
+ '㊵' => '40',
+ '㊶' => '41',
+ '㊷' => '42',
+ '㊸' => '43',
+ '㊹' => '44',
+ '㊺' => '45',
+ '㊻' => '46',
+ '㊼' => '47',
+ '㊽' => '48',
+ '㊾' => '49',
+ '㊿' => '50',
+ '㋀' => '1月',
+ '㋁' => '2月',
+ '㋂' => '3月',
+ '㋃' => '4月',
+ '㋄' => '5月',
+ '㋅' => '6月',
+ '㋆' => '7月',
+ '㋇' => '8月',
+ '㋈' => '9月',
+ '㋉' => '10月',
+ '㋊' => '11月',
+ '㋋' => '12月',
+ '㋌' => 'Hg',
+ '㋍' => 'erg',
+ '㋎' => 'eV',
+ '㋏' => 'LTD',
+ '㋐' => 'ア',
+ '㋑' => 'イ',
+ '㋒' => 'ウ',
+ '㋓' => 'エ',
+ '㋔' => 'オ',
+ '㋕' => 'カ',
+ '㋖' => 'キ',
+ '㋗' => 'ク',
+ '㋘' => 'ケ',
+ '㋙' => 'コ',
+ '㋚' => 'サ',
+ '㋛' => 'シ',
+ '㋜' => 'ス',
+ '㋝' => 'セ',
+ '㋞' => 'ソ',
+ '㋟' => 'タ',
+ '㋠' => 'チ',
+ '㋡' => 'ツ',
+ '㋢' => 'テ',
+ '㋣' => 'ト',
+ '㋤' => 'ナ',
+ '㋥' => 'ニ',
+ '㋦' => 'ヌ',
+ '㋧' => 'ネ',
+ '㋨' => 'ノ',
+ '㋩' => 'ハ',
+ '㋪' => 'ヒ',
+ '㋫' => 'フ',
+ '㋬' => 'ヘ',
+ '㋭' => 'ホ',
+ '㋮' => 'マ',
+ '㋯' => 'ミ',
+ '㋰' => 'ム',
+ '㋱' => 'メ',
+ '㋲' => 'モ',
+ '㋳' => 'ヤ',
+ '㋴' => 'ユ',
+ '㋵' => 'ヨ',
+ '㋶' => 'ラ',
+ '㋷' => 'リ',
+ '㋸' => 'ル',
+ '㋹' => 'レ',
+ '㋺' => 'ロ',
+ '㋻' => 'ワ',
+ '㋼' => 'ヰ',
+ '㋽' => 'ヱ',
+ '㋾' => 'ヲ',
+ '㋿' => '令和',
+ '㌀' => 'アパート',
+ '㌁' => 'アルファ',
+ '㌂' => 'アンペア',
+ '㌃' => 'アール',
+ '㌄' => 'イニング',
+ '㌅' => 'インチ',
+ '㌆' => 'ウォン',
+ '㌇' => 'エスクード',
+ '㌈' => 'エーカー',
+ '㌉' => 'オンス',
+ '㌊' => 'オーム',
+ '㌋' => 'カイリ',
+ '㌌' => 'カラット',
+ '㌍' => 'カロリー',
+ '㌎' => 'ガロン',
+ '㌏' => 'ガンマ',
+ '㌐' => 'ギガ',
+ '㌑' => 'ギニー',
+ '㌒' => 'キュリー',
+ '㌓' => 'ギルダー',
+ '㌔' => 'キロ',
+ '㌕' => 'キログラム',
+ '㌖' => 'キロメートル',
+ '㌗' => 'キロワット',
+ '㌘' => 'グラム',
+ '㌙' => 'グラムトン',
+ '㌚' => 'クルゼイロ',
+ '㌛' => 'クローネ',
+ '㌜' => 'ケース',
+ '㌝' => 'コルナ',
+ '㌞' => 'コーポ',
+ '㌟' => 'サイクル',
+ '㌠' => 'サンチーム',
+ '㌡' => 'シリング',
+ '㌢' => 'センチ',
+ '㌣' => 'セント',
+ '㌤' => 'ダース',
+ '㌥' => 'デシ',
+ '㌦' => 'ドル',
+ '㌧' => 'トン',
+ '㌨' => 'ナノ',
+ '㌩' => 'ノット',
+ '㌪' => 'ハイツ',
+ '㌫' => 'パーセント',
+ '㌬' => 'パーツ',
+ '㌭' => 'バーレル',
+ '㌮' => 'ピアストル',
+ '㌯' => 'ピクル',
+ '㌰' => 'ピコ',
+ '㌱' => 'ビル',
+ '㌲' => 'ファラッド',
+ '㌳' => 'フィート',
+ '㌴' => 'ブッシェル',
+ '㌵' => 'フラン',
+ '㌶' => 'ヘクタール',
+ '㌷' => 'ペソ',
+ '㌸' => 'ペニヒ',
+ '㌹' => 'ヘルツ',
+ '㌺' => 'ペンス',
+ '㌻' => 'ページ',
+ '㌼' => 'ベータ',
+ '㌽' => 'ポイント',
+ '㌾' => 'ボルト',
+ '㌿' => 'ホン',
+ '㍀' => 'ポンド',
+ '㍁' => 'ホール',
+ '㍂' => 'ホーン',
+ '㍃' => 'マイクロ',
+ '㍄' => 'マイル',
+ '㍅' => 'マッハ',
+ '㍆' => 'マルク',
+ '㍇' => 'マンション',
+ '㍈' => 'ミクロン',
+ '㍉' => 'ミリ',
+ '㍊' => 'ミリバール',
+ '㍋' => 'メガ',
+ '㍌' => 'メガトン',
+ '㍍' => 'メートル',
+ '㍎' => 'ヤード',
+ '㍏' => 'ヤール',
+ '㍐' => 'ユアン',
+ '㍑' => 'リットル',
+ '㍒' => 'リラ',
+ '㍓' => 'ルピー',
+ '㍔' => 'ルーブル',
+ '㍕' => 'レム',
+ '㍖' => 'レントゲン',
+ '㍗' => 'ワット',
+ '㍘' => '0点',
+ '㍙' => '1点',
+ '㍚' => '2点',
+ '㍛' => '3点',
+ '㍜' => '4点',
+ '㍝' => '5点',
+ '㍞' => '6点',
+ '㍟' => '7点',
+ '㍠' => '8点',
+ '㍡' => '9点',
+ '㍢' => '10点',
+ '㍣' => '11点',
+ '㍤' => '12点',
+ '㍥' => '13点',
+ '㍦' => '14点',
+ '㍧' => '15点',
+ '㍨' => '16点',
+ '㍩' => '17点',
+ '㍪' => '18点',
+ '㍫' => '19点',
+ '㍬' => '20点',
+ '㍭' => '21点',
+ '㍮' => '22点',
+ '㍯' => '23点',
+ '㍰' => '24点',
+ '㍱' => 'hPa',
+ '㍲' => 'da',
+ '㍳' => 'AU',
+ '㍴' => 'bar',
+ '㍵' => 'oV',
+ '㍶' => 'pc',
+ '㍷' => 'dm',
+ '㍸' => 'dm2',
+ '㍹' => 'dm3',
+ '㍺' => 'IU',
+ '㍻' => '平成',
+ '㍼' => '昭和',
+ '㍽' => '大正',
+ '㍾' => '明治',
+ '㍿' => '株式会社',
+ '㎀' => 'pA',
+ '㎁' => 'nA',
+ '㎂' => 'μA',
+ '㎃' => 'mA',
+ '㎄' => 'kA',
+ '㎅' => 'KB',
+ '㎆' => 'MB',
+ '㎇' => 'GB',
+ '㎈' => 'cal',
+ '㎉' => 'kcal',
+ '㎊' => 'pF',
+ '㎋' => 'nF',
+ '㎌' => 'μF',
+ '㎍' => 'μg',
+ '㎎' => 'mg',
+ '㎏' => 'kg',
+ '㎐' => 'Hz',
+ '㎑' => 'kHz',
+ '㎒' => 'MHz',
+ '㎓' => 'GHz',
+ '㎔' => 'THz',
+ '㎕' => 'μl',
+ '㎖' => 'ml',
+ '㎗' => 'dl',
+ '㎘' => 'kl',
+ '㎙' => 'fm',
+ '㎚' => 'nm',
+ '㎛' => 'μm',
+ '㎜' => 'mm',
+ '㎝' => 'cm',
+ '㎞' => 'km',
+ '㎟' => 'mm2',
+ '㎠' => 'cm2',
+ '㎡' => 'm2',
+ '㎢' => 'km2',
+ '㎣' => 'mm3',
+ '㎤' => 'cm3',
+ '㎥' => 'm3',
+ '㎦' => 'km3',
+ '㎧' => 'm∕s',
+ '㎨' => 'm∕s2',
+ '㎩' => 'Pa',
+ '㎪' => 'kPa',
+ '㎫' => 'MPa',
+ '㎬' => 'GPa',
+ '㎭' => 'rad',
+ '㎮' => 'rad∕s',
+ '㎯' => 'rad∕s2',
+ '㎰' => 'ps',
+ '㎱' => 'ns',
+ '㎲' => 'μs',
+ '㎳' => 'ms',
+ '㎴' => 'pV',
+ '㎵' => 'nV',
+ '㎶' => 'μV',
+ '㎷' => 'mV',
+ '㎸' => 'kV',
+ '㎹' => 'MV',
+ '㎺' => 'pW',
+ '㎻' => 'nW',
+ '㎼' => 'μW',
+ '㎽' => 'mW',
+ '㎾' => 'kW',
+ '㎿' => 'MW',
+ '㏀' => 'kΩ',
+ '㏁' => 'MΩ',
+ '㏂' => 'a.m.',
+ '㏃' => 'Bq',
+ '㏄' => 'cc',
+ '㏅' => 'cd',
+ '㏆' => 'C∕kg',
+ '㏇' => 'Co.',
+ '㏈' => 'dB',
+ '㏉' => 'Gy',
+ '㏊' => 'ha',
+ '㏋' => 'HP',
+ '㏌' => 'in',
+ '㏍' => 'KK',
+ '㏎' => 'KM',
+ '㏏' => 'kt',
+ '㏐' => 'lm',
+ '㏑' => 'ln',
+ '㏒' => 'log',
+ '㏓' => 'lx',
+ '㏔' => 'mb',
+ '㏕' => 'mil',
+ '㏖' => 'mol',
+ '㏗' => 'PH',
+ '㏘' => 'p.m.',
+ '㏙' => 'PPM',
+ '㏚' => 'PR',
+ '㏛' => 'sr',
+ '㏜' => 'Sv',
+ '㏝' => 'Wb',
+ '㏞' => 'V∕m',
+ '㏟' => 'A∕m',
+ '㏠' => '1日',
+ '㏡' => '2日',
+ '㏢' => '3日',
+ '㏣' => '4日',
+ '㏤' => '5日',
+ '㏥' => '6日',
+ '㏦' => '7日',
+ '㏧' => '8日',
+ '㏨' => '9日',
+ '㏩' => '10日',
+ '㏪' => '11日',
+ '㏫' => '12日',
+ '㏬' => '13日',
+ '㏭' => '14日',
+ '㏮' => '15日',
+ '㏯' => '16日',
+ '㏰' => '17日',
+ '㏱' => '18日',
+ '㏲' => '19日',
+ '㏳' => '20日',
+ '㏴' => '21日',
+ '㏵' => '22日',
+ '㏶' => '23日',
+ '㏷' => '24日',
+ '㏸' => '25日',
+ '㏹' => '26日',
+ '㏺' => '27日',
+ '㏻' => '28日',
+ '㏼' => '29日',
+ '㏽' => '30日',
+ '㏾' => '31日',
+ '㏿' => 'gal',
+ 'ꚜ' => 'ъ',
+ 'ꚝ' => 'ь',
+ 'ꝰ' => 'ꝯ',
+ 'ꟸ' => 'Ħ',
+ 'ꟹ' => 'œ',
+ 'ꭜ' => 'ꜧ',
+ 'ꭝ' => 'ꬷ',
+ 'ꭞ' => 'ɫ',
+ 'ꭟ' => 'ꭒ',
+ 'ꭩ' => 'ʍ',
+ 'ff' => 'ff',
+ 'fi' => 'fi',
+ 'fl' => 'fl',
+ 'ffi' => 'ffi',
+ 'ffl' => 'ffl',
+ 'ſt' => 'st',
+ 'st' => 'st',
+ 'ﬓ' => 'մն',
+ 'ﬔ' => 'մե',
+ 'ﬕ' => 'մի',
+ 'ﬖ' => 'վն',
+ 'ﬗ' => 'մխ',
+ 'ﬠ' => 'ע',
+ 'ﬡ' => 'א',
+ 'ﬢ' => 'ד',
+ 'ﬣ' => 'ה',
+ 'ﬤ' => 'כ',
+ 'ﬥ' => 'ל',
+ 'ﬦ' => 'ם',
+ 'ﬧ' => 'ר',
+ 'ﬨ' => 'ת',
+ '﬩' => '+',
+ 'ﭏ' => 'אל',
+ 'ﭐ' => 'ٱ',
+ 'ﭑ' => 'ٱ',
+ 'ﭒ' => 'ٻ',
+ 'ﭓ' => 'ٻ',
+ 'ﭔ' => 'ٻ',
+ 'ﭕ' => 'ٻ',
+ 'ﭖ' => 'پ',
+ 'ﭗ' => 'پ',
+ 'ﭘ' => 'پ',
+ 'ﭙ' => 'پ',
+ 'ﭚ' => 'ڀ',
+ 'ﭛ' => 'ڀ',
+ 'ﭜ' => 'ڀ',
+ 'ﭝ' => 'ڀ',
+ 'ﭞ' => 'ٺ',
+ 'ﭟ' => 'ٺ',
+ 'ﭠ' => 'ٺ',
+ 'ﭡ' => 'ٺ',
+ 'ﭢ' => 'ٿ',
+ 'ﭣ' => 'ٿ',
+ 'ﭤ' => 'ٿ',
+ 'ﭥ' => 'ٿ',
+ 'ﭦ' => 'ٹ',
+ 'ﭧ' => 'ٹ',
+ 'ﭨ' => 'ٹ',
+ 'ﭩ' => 'ٹ',
+ 'ﭪ' => 'ڤ',
+ 'ﭫ' => 'ڤ',
+ 'ﭬ' => 'ڤ',
+ 'ﭭ' => 'ڤ',
+ 'ﭮ' => 'ڦ',
+ 'ﭯ' => 'ڦ',
+ 'ﭰ' => 'ڦ',
+ 'ﭱ' => 'ڦ',
+ 'ﭲ' => 'ڄ',
+ 'ﭳ' => 'ڄ',
+ 'ﭴ' => 'ڄ',
+ 'ﭵ' => 'ڄ',
+ 'ﭶ' => 'ڃ',
+ 'ﭷ' => 'ڃ',
+ 'ﭸ' => 'ڃ',
+ 'ﭹ' => 'ڃ',
+ 'ﭺ' => 'چ',
+ 'ﭻ' => 'چ',
+ 'ﭼ' => 'چ',
+ 'ﭽ' => 'چ',
+ 'ﭾ' => 'ڇ',
+ 'ﭿ' => 'ڇ',
+ 'ﮀ' => 'ڇ',
+ 'ﮁ' => 'ڇ',
+ 'ﮂ' => 'ڍ',
+ 'ﮃ' => 'ڍ',
+ 'ﮄ' => 'ڌ',
+ 'ﮅ' => 'ڌ',
+ 'ﮆ' => 'ڎ',
+ 'ﮇ' => 'ڎ',
+ 'ﮈ' => 'ڈ',
+ 'ﮉ' => 'ڈ',
+ 'ﮊ' => 'ژ',
+ 'ﮋ' => 'ژ',
+ 'ﮌ' => 'ڑ',
+ 'ﮍ' => 'ڑ',
+ 'ﮎ' => 'ک',
+ 'ﮏ' => 'ک',
+ 'ﮐ' => 'ک',
+ 'ﮑ' => 'ک',
+ 'ﮒ' => 'گ',
+ 'ﮓ' => 'گ',
+ 'ﮔ' => 'گ',
+ 'ﮕ' => 'گ',
+ 'ﮖ' => 'ڳ',
+ 'ﮗ' => 'ڳ',
+ 'ﮘ' => 'ڳ',
+ 'ﮙ' => 'ڳ',
+ 'ﮚ' => 'ڱ',
+ 'ﮛ' => 'ڱ',
+ 'ﮜ' => 'ڱ',
+ 'ﮝ' => 'ڱ',
+ 'ﮞ' => 'ں',
+ 'ﮟ' => 'ں',
+ 'ﮠ' => 'ڻ',
+ 'ﮡ' => 'ڻ',
+ 'ﮢ' => 'ڻ',
+ 'ﮣ' => 'ڻ',
+ 'ﮤ' => 'ۀ',
+ 'ﮥ' => 'ۀ',
+ 'ﮦ' => 'ہ',
+ 'ﮧ' => 'ہ',
+ 'ﮨ' => 'ہ',
+ 'ﮩ' => 'ہ',
+ 'ﮪ' => 'ھ',
+ 'ﮫ' => 'ھ',
+ 'ﮬ' => 'ھ',
+ 'ﮭ' => 'ھ',
+ 'ﮮ' => 'ے',
+ 'ﮯ' => 'ے',
+ 'ﮰ' => 'ۓ',
+ 'ﮱ' => 'ۓ',
+ 'ﯓ' => 'ڭ',
+ 'ﯔ' => 'ڭ',
+ 'ﯕ' => 'ڭ',
+ 'ﯖ' => 'ڭ',
+ 'ﯗ' => 'ۇ',
+ 'ﯘ' => 'ۇ',
+ 'ﯙ' => 'ۆ',
+ 'ﯚ' => 'ۆ',
+ 'ﯛ' => 'ۈ',
+ 'ﯜ' => 'ۈ',
+ 'ﯝ' => 'ۇٴ',
+ 'ﯞ' => 'ۋ',
+ 'ﯟ' => 'ۋ',
+ 'ﯠ' => 'ۅ',
+ 'ﯡ' => 'ۅ',
+ 'ﯢ' => 'ۉ',
+ 'ﯣ' => 'ۉ',
+ 'ﯤ' => 'ې',
+ 'ﯥ' => 'ې',
+ 'ﯦ' => 'ې',
+ 'ﯧ' => 'ې',
+ 'ﯨ' => 'ى',
+ 'ﯩ' => 'ى',
+ 'ﯪ' => 'ئا',
+ 'ﯫ' => 'ئا',
+ 'ﯬ' => 'ئە',
+ 'ﯭ' => 'ئە',
+ 'ﯮ' => 'ئو',
+ 'ﯯ' => 'ئو',
+ 'ﯰ' => 'ئۇ',
+ 'ﯱ' => 'ئۇ',
+ 'ﯲ' => 'ئۆ',
+ 'ﯳ' => 'ئۆ',
+ 'ﯴ' => 'ئۈ',
+ 'ﯵ' => 'ئۈ',
+ 'ﯶ' => 'ئې',
+ 'ﯷ' => 'ئې',
+ 'ﯸ' => 'ئې',
+ 'ﯹ' => 'ئى',
+ 'ﯺ' => 'ئى',
+ 'ﯻ' => 'ئى',
+ 'ﯼ' => 'ی',
+ 'ﯽ' => 'ی',
+ 'ﯾ' => 'ی',
+ 'ﯿ' => 'ی',
+ 'ﰀ' => 'ئج',
+ 'ﰁ' => 'ئح',
+ 'ﰂ' => 'ئم',
+ 'ﰃ' => 'ئى',
+ 'ﰄ' => 'ئي',
+ 'ﰅ' => 'بج',
+ 'ﰆ' => 'بح',
+ 'ﰇ' => 'بخ',
+ 'ﰈ' => 'بم',
+ 'ﰉ' => 'بى',
+ 'ﰊ' => 'بي',
+ 'ﰋ' => 'تج',
+ 'ﰌ' => 'تح',
+ 'ﰍ' => 'تخ',
+ 'ﰎ' => 'تم',
+ 'ﰏ' => 'تى',
+ 'ﰐ' => 'تي',
+ 'ﰑ' => 'ثج',
+ 'ﰒ' => 'ثم',
+ 'ﰓ' => 'ثى',
+ 'ﰔ' => 'ثي',
+ 'ﰕ' => 'جح',
+ 'ﰖ' => 'جم',
+ 'ﰗ' => 'حج',
+ 'ﰘ' => 'حم',
+ 'ﰙ' => 'خج',
+ 'ﰚ' => 'خح',
+ 'ﰛ' => 'خم',
+ 'ﰜ' => 'سج',
+ 'ﰝ' => 'سح',
+ 'ﰞ' => 'سخ',
+ 'ﰟ' => 'سم',
+ 'ﰠ' => 'صح',
+ 'ﰡ' => 'صم',
+ 'ﰢ' => 'ضج',
+ 'ﰣ' => 'ضح',
+ 'ﰤ' => 'ضخ',
+ 'ﰥ' => 'ضم',
+ 'ﰦ' => 'طح',
+ 'ﰧ' => 'طم',
+ 'ﰨ' => 'ظم',
+ 'ﰩ' => 'عج',
+ 'ﰪ' => 'عم',
+ 'ﰫ' => 'غج',
+ 'ﰬ' => 'غم',
+ 'ﰭ' => 'فج',
+ 'ﰮ' => 'فح',
+ 'ﰯ' => 'فخ',
+ 'ﰰ' => 'فم',
+ 'ﰱ' => 'فى',
+ 'ﰲ' => 'في',
+ 'ﰳ' => 'قح',
+ 'ﰴ' => 'قم',
+ 'ﰵ' => 'قى',
+ 'ﰶ' => 'قي',
+ 'ﰷ' => 'كا',
+ 'ﰸ' => 'كج',
+ 'ﰹ' => 'كح',
+ 'ﰺ' => 'كخ',
+ 'ﰻ' => 'كل',
+ 'ﰼ' => 'كم',
+ 'ﰽ' => 'كى',
+ 'ﰾ' => 'كي',
+ 'ﰿ' => 'لج',
+ 'ﱀ' => 'لح',
+ 'ﱁ' => 'لخ',
+ 'ﱂ' => 'لم',
+ 'ﱃ' => 'لى',
+ 'ﱄ' => 'لي',
+ 'ﱅ' => 'مج',
+ 'ﱆ' => 'مح',
+ 'ﱇ' => 'مخ',
+ 'ﱈ' => 'مم',
+ 'ﱉ' => 'مى',
+ 'ﱊ' => 'مي',
+ 'ﱋ' => 'نج',
+ 'ﱌ' => 'نح',
+ 'ﱍ' => 'نخ',
+ 'ﱎ' => 'نم',
+ 'ﱏ' => 'نى',
+ 'ﱐ' => 'ني',
+ 'ﱑ' => 'هج',
+ 'ﱒ' => 'هم',
+ 'ﱓ' => 'هى',
+ 'ﱔ' => 'هي',
+ 'ﱕ' => 'يج',
+ 'ﱖ' => 'يح',
+ 'ﱗ' => 'يخ',
+ 'ﱘ' => 'يم',
+ 'ﱙ' => 'يى',
+ 'ﱚ' => 'يي',
+ 'ﱛ' => 'ذٰ',
+ 'ﱜ' => 'رٰ',
+ 'ﱝ' => 'ىٰ',
+ 'ﱞ' => ' ٌّ',
+ 'ﱟ' => ' ٍّ',
+ 'ﱠ' => ' َّ',
+ 'ﱡ' => ' ُّ',
+ 'ﱢ' => ' ِّ',
+ 'ﱣ' => ' ّٰ',
+ 'ﱤ' => 'ئر',
+ 'ﱥ' => 'ئز',
+ 'ﱦ' => 'ئم',
+ 'ﱧ' => 'ئن',
+ 'ﱨ' => 'ئى',
+ 'ﱩ' => 'ئي',
+ 'ﱪ' => 'بر',
+ 'ﱫ' => 'بز',
+ 'ﱬ' => 'بم',
+ 'ﱭ' => 'بن',
+ 'ﱮ' => 'بى',
+ 'ﱯ' => 'بي',
+ 'ﱰ' => 'تر',
+ 'ﱱ' => 'تز',
+ 'ﱲ' => 'تم',
+ 'ﱳ' => 'تن',
+ 'ﱴ' => 'تى',
+ 'ﱵ' => 'تي',
+ 'ﱶ' => 'ثر',
+ 'ﱷ' => 'ثز',
+ 'ﱸ' => 'ثم',
+ 'ﱹ' => 'ثن',
+ 'ﱺ' => 'ثى',
+ 'ﱻ' => 'ثي',
+ 'ﱼ' => 'فى',
+ 'ﱽ' => 'في',
+ 'ﱾ' => 'قى',
+ 'ﱿ' => 'قي',
+ 'ﲀ' => 'كا',
+ 'ﲁ' => 'كل',
+ 'ﲂ' => 'كم',
+ 'ﲃ' => 'كى',
+ 'ﲄ' => 'كي',
+ 'ﲅ' => 'لم',
+ 'ﲆ' => 'لى',
+ 'ﲇ' => 'لي',
+ 'ﲈ' => 'ما',
+ 'ﲉ' => 'مم',
+ 'ﲊ' => 'نر',
+ 'ﲋ' => 'نز',
+ 'ﲌ' => 'نم',
+ 'ﲍ' => 'نن',
+ 'ﲎ' => 'نى',
+ 'ﲏ' => 'ني',
+ 'ﲐ' => 'ىٰ',
+ 'ﲑ' => 'ير',
+ 'ﲒ' => 'يز',
+ 'ﲓ' => 'يم',
+ 'ﲔ' => 'ين',
+ 'ﲕ' => 'يى',
+ 'ﲖ' => 'يي',
+ 'ﲗ' => 'ئج',
+ 'ﲘ' => 'ئح',
+ 'ﲙ' => 'ئخ',
+ 'ﲚ' => 'ئم',
+ 'ﲛ' => 'ئه',
+ 'ﲜ' => 'بج',
+ 'ﲝ' => 'بح',
+ 'ﲞ' => 'بخ',
+ 'ﲟ' => 'بم',
+ 'ﲠ' => 'به',
+ 'ﲡ' => 'تج',
+ 'ﲢ' => 'تح',
+ 'ﲣ' => 'تخ',
+ 'ﲤ' => 'تم',
+ 'ﲥ' => 'ته',
+ 'ﲦ' => 'ثم',
+ 'ﲧ' => 'جح',
+ 'ﲨ' => 'جم',
+ 'ﲩ' => 'حج',
+ 'ﲪ' => 'حم',
+ 'ﲫ' => 'خج',
+ 'ﲬ' => 'خم',
+ 'ﲭ' => 'سج',
+ 'ﲮ' => 'سح',
+ 'ﲯ' => 'سخ',
+ 'ﲰ' => 'سم',
+ 'ﲱ' => 'صح',
+ 'ﲲ' => 'صخ',
+ 'ﲳ' => 'صم',
+ 'ﲴ' => 'ضج',
+ 'ﲵ' => 'ضح',
+ 'ﲶ' => 'ضخ',
+ 'ﲷ' => 'ضم',
+ 'ﲸ' => 'طح',
+ 'ﲹ' => 'ظم',
+ 'ﲺ' => 'عج',
+ 'ﲻ' => 'عم',
+ 'ﲼ' => 'غج',
+ 'ﲽ' => 'غم',
+ 'ﲾ' => 'فج',
+ 'ﲿ' => 'فح',
+ 'ﳀ' => 'فخ',
+ 'ﳁ' => 'فم',
+ 'ﳂ' => 'قح',
+ 'ﳃ' => 'قم',
+ 'ﳄ' => 'كج',
+ 'ﳅ' => 'كح',
+ 'ﳆ' => 'كخ',
+ 'ﳇ' => 'كل',
+ 'ﳈ' => 'كم',
+ 'ﳉ' => 'لج',
+ 'ﳊ' => 'لح',
+ 'ﳋ' => 'لخ',
+ 'ﳌ' => 'لم',
+ 'ﳍ' => 'له',
+ 'ﳎ' => 'مج',
+ 'ﳏ' => 'مح',
+ 'ﳐ' => 'مخ',
+ 'ﳑ' => 'مم',
+ 'ﳒ' => 'نج',
+ 'ﳓ' => 'نح',
+ 'ﳔ' => 'نخ',
+ 'ﳕ' => 'نم',
+ 'ﳖ' => 'نه',
+ 'ﳗ' => 'هج',
+ 'ﳘ' => 'هم',
+ 'ﳙ' => 'هٰ',
+ 'ﳚ' => 'يج',
+ 'ﳛ' => 'يح',
+ 'ﳜ' => 'يخ',
+ 'ﳝ' => 'يم',
+ 'ﳞ' => 'يه',
+ 'ﳟ' => 'ئم',
+ 'ﳠ' => 'ئه',
+ 'ﳡ' => 'بم',
+ 'ﳢ' => 'به',
+ 'ﳣ' => 'تم',
+ 'ﳤ' => 'ته',
+ 'ﳥ' => 'ثم',
+ 'ﳦ' => 'ثه',
+ 'ﳧ' => 'سم',
+ 'ﳨ' => 'سه',
+ 'ﳩ' => 'شم',
+ 'ﳪ' => 'شه',
+ 'ﳫ' => 'كل',
+ 'ﳬ' => 'كم',
+ 'ﳭ' => 'لم',
+ 'ﳮ' => 'نم',
+ 'ﳯ' => 'نه',
+ 'ﳰ' => 'يم',
+ 'ﳱ' => 'يه',
+ 'ﳲ' => 'ـَّ',
+ 'ﳳ' => 'ـُّ',
+ 'ﳴ' => 'ـِّ',
+ 'ﳵ' => 'طى',
+ 'ﳶ' => 'طي',
+ 'ﳷ' => 'عى',
+ 'ﳸ' => 'عي',
+ 'ﳹ' => 'غى',
+ 'ﳺ' => 'غي',
+ 'ﳻ' => 'سى',
+ 'ﳼ' => 'سي',
+ 'ﳽ' => 'شى',
+ 'ﳾ' => 'شي',
+ 'ﳿ' => 'حى',
+ 'ﴀ' => 'حي',
+ 'ﴁ' => 'جى',
+ 'ﴂ' => 'جي',
+ 'ﴃ' => 'خى',
+ 'ﴄ' => 'خي',
+ 'ﴅ' => 'صى',
+ 'ﴆ' => 'صي',
+ 'ﴇ' => 'ضى',
+ 'ﴈ' => 'ضي',
+ 'ﴉ' => 'شج',
+ 'ﴊ' => 'شح',
+ 'ﴋ' => 'شخ',
+ 'ﴌ' => 'شم',
+ 'ﴍ' => 'شر',
+ 'ﴎ' => 'سر',
+ 'ﴏ' => 'صر',
+ 'ﴐ' => 'ضر',
+ 'ﴑ' => 'طى',
+ 'ﴒ' => 'طي',
+ 'ﴓ' => 'عى',
+ 'ﴔ' => 'عي',
+ 'ﴕ' => 'غى',
+ 'ﴖ' => 'غي',
+ 'ﴗ' => 'سى',
+ 'ﴘ' => 'سي',
+ 'ﴙ' => 'شى',
+ 'ﴚ' => 'شي',
+ 'ﴛ' => 'حى',
+ 'ﴜ' => 'حي',
+ 'ﴝ' => 'جى',
+ 'ﴞ' => 'جي',
+ 'ﴟ' => 'خى',
+ 'ﴠ' => 'خي',
+ 'ﴡ' => 'صى',
+ 'ﴢ' => 'صي',
+ 'ﴣ' => 'ضى',
+ 'ﴤ' => 'ضي',
+ 'ﴥ' => 'شج',
+ 'ﴦ' => 'شح',
+ 'ﴧ' => 'شخ',
+ 'ﴨ' => 'شم',
+ 'ﴩ' => 'شر',
+ 'ﴪ' => 'سر',
+ 'ﴫ' => 'صر',
+ 'ﴬ' => 'ضر',
+ 'ﴭ' => 'شج',
+ 'ﴮ' => 'شح',
+ 'ﴯ' => 'شخ',
+ 'ﴰ' => 'شم',
+ 'ﴱ' => 'سه',
+ 'ﴲ' => 'شه',
+ 'ﴳ' => 'طم',
+ 'ﴴ' => 'سج',
+ 'ﴵ' => 'سح',
+ 'ﴶ' => 'سخ',
+ 'ﴷ' => 'شج',
+ 'ﴸ' => 'شح',
+ 'ﴹ' => 'شخ',
+ 'ﴺ' => 'طم',
+ 'ﴻ' => 'ظم',
+ 'ﴼ' => 'اً',
+ 'ﴽ' => 'اً',
+ 'ﵐ' => 'تجم',
+ 'ﵑ' => 'تحج',
+ 'ﵒ' => 'تحج',
+ 'ﵓ' => 'تحم',
+ 'ﵔ' => 'تخم',
+ 'ﵕ' => 'تمج',
+ 'ﵖ' => 'تمح',
+ 'ﵗ' => 'تمخ',
+ 'ﵘ' => 'جمح',
+ 'ﵙ' => 'جمح',
+ 'ﵚ' => 'حمي',
+ 'ﵛ' => 'حمى',
+ 'ﵜ' => 'سحج',
+ 'ﵝ' => 'سجح',
+ 'ﵞ' => 'سجى',
+ 'ﵟ' => 'سمح',
+ 'ﵠ' => 'سمح',
+ 'ﵡ' => 'سمج',
+ 'ﵢ' => 'سمم',
+ 'ﵣ' => 'سمم',
+ 'ﵤ' => 'صحح',
+ 'ﵥ' => 'صحح',
+ 'ﵦ' => 'صمم',
+ 'ﵧ' => 'شحم',
+ 'ﵨ' => 'شحم',
+ 'ﵩ' => 'شجي',
+ 'ﵪ' => 'شمخ',
+ 'ﵫ' => 'شمخ',
+ 'ﵬ' => 'شمم',
+ 'ﵭ' => 'شمم',
+ 'ﵮ' => 'ضحى',
+ 'ﵯ' => 'ضخم',
+ 'ﵰ' => 'ضخم',
+ 'ﵱ' => 'طمح',
+ 'ﵲ' => 'طمح',
+ 'ﵳ' => 'طمم',
+ 'ﵴ' => 'طمي',
+ 'ﵵ' => 'عجم',
+ 'ﵶ' => 'عمم',
+ 'ﵷ' => 'عمم',
+ 'ﵸ' => 'عمى',
+ 'ﵹ' => 'غمم',
+ 'ﵺ' => 'غمي',
+ 'ﵻ' => 'غمى',
+ 'ﵼ' => 'فخم',
+ 'ﵽ' => 'فخم',
+ 'ﵾ' => 'قمح',
+ 'ﵿ' => 'قمم',
+ 'ﶀ' => 'لحم',
+ 'ﶁ' => 'لحي',
+ 'ﶂ' => 'لحى',
+ 'ﶃ' => 'لجج',
+ 'ﶄ' => 'لجج',
+ 'ﶅ' => 'لخم',
+ 'ﶆ' => 'لخم',
+ 'ﶇ' => 'لمح',
+ 'ﶈ' => 'لمح',
+ 'ﶉ' => 'محج',
+ 'ﶊ' => 'محم',
+ 'ﶋ' => 'محي',
+ 'ﶌ' => 'مجح',
+ 'ﶍ' => 'مجم',
+ 'ﶎ' => 'مخج',
+ 'ﶏ' => 'مخم',
+ 'ﶒ' => 'مجخ',
+ 'ﶓ' => 'همج',
+ 'ﶔ' => 'همم',
+ 'ﶕ' => 'نحم',
+ 'ﶖ' => 'نحى',
+ 'ﶗ' => 'نجم',
+ 'ﶘ' => 'نجم',
+ 'ﶙ' => 'نجى',
+ 'ﶚ' => 'نمي',
+ 'ﶛ' => 'نمى',
+ 'ﶜ' => 'يمم',
+ 'ﶝ' => 'يمم',
+ 'ﶞ' => 'بخي',
+ 'ﶟ' => 'تجي',
+ 'ﶠ' => 'تجى',
+ 'ﶡ' => 'تخي',
+ 'ﶢ' => 'تخى',
+ 'ﶣ' => 'تمي',
+ 'ﶤ' => 'تمى',
+ 'ﶥ' => 'جمي',
+ 'ﶦ' => 'جحى',
+ 'ﶧ' => 'جمى',
+ 'ﶨ' => 'سخى',
+ 'ﶩ' => 'صحي',
+ 'ﶪ' => 'شحي',
+ 'ﶫ' => 'ضحي',
+ 'ﶬ' => 'لجي',
+ 'ﶭ' => 'لمي',
+ 'ﶮ' => 'يحي',
+ 'ﶯ' => 'يجي',
+ 'ﶰ' => 'يمي',
+ 'ﶱ' => 'ممي',
+ 'ﶲ' => 'قمي',
+ 'ﶳ' => 'نحي',
+ 'ﶴ' => 'قمح',
+ 'ﶵ' => 'لحم',
+ 'ﶶ' => 'عمي',
+ 'ﶷ' => 'كمي',
+ 'ﶸ' => 'نجح',
+ 'ﶹ' => 'مخي',
+ 'ﶺ' => 'لجم',
+ 'ﶻ' => 'كمم',
+ 'ﶼ' => 'لجم',
+ 'ﶽ' => 'نجح',
+ 'ﶾ' => 'جحي',
+ 'ﶿ' => 'حجي',
+ 'ﷀ' => 'مجي',
+ 'ﷁ' => 'فمي',
+ 'ﷂ' => 'بحي',
+ 'ﷃ' => 'كمم',
+ 'ﷄ' => 'عجم',
+ 'ﷅ' => 'صمم',
+ 'ﷆ' => 'سخي',
+ 'ﷇ' => 'نجي',
+ 'ﷰ' => 'صلے',
+ 'ﷱ' => 'قلے',
+ 'ﷲ' => 'الله',
+ 'ﷳ' => 'اكبر',
+ 'ﷴ' => 'محمد',
+ 'ﷵ' => 'صلعم',
+ 'ﷶ' => 'رسول',
+ 'ﷷ' => 'عليه',
+ 'ﷸ' => 'وسلم',
+ 'ﷹ' => 'صلى',
+ 'ﷺ' => 'صلى الله عليه وسلم',
+ 'ﷻ' => 'جل جلاله',
+ '﷼' => 'ریال',
+ '︐' => ',',
+ '︑' => '、',
+ '︒' => '。',
+ '︓' => ':',
+ '︔' => ';',
+ '︕' => '!',
+ '︖' => '?',
+ '︗' => '〖',
+ '︘' => '〗',
+ '︙' => '...',
+ '︰' => '..',
+ '︱' => '—',
+ '︲' => '–',
+ '︳' => '_',
+ '︴' => '_',
+ '︵' => '(',
+ '︶' => ')',
+ '︷' => '{',
+ '︸' => '}',
+ '︹' => '〔',
+ '︺' => '〕',
+ '︻' => '【',
+ '︼' => '】',
+ '︽' => '《',
+ '︾' => '》',
+ '︿' => '〈',
+ '﹀' => '〉',
+ '﹁' => '「',
+ '﹂' => '」',
+ '﹃' => '『',
+ '﹄' => '』',
+ '﹇' => '[',
+ '﹈' => ']',
+ '﹉' => ' ̅',
+ '﹊' => ' ̅',
+ '﹋' => ' ̅',
+ '﹌' => ' ̅',
+ '﹍' => '_',
+ '﹎' => '_',
+ '﹏' => '_',
+ '﹐' => ',',
+ '﹑' => '、',
+ '﹒' => '.',
+ '﹔' => ';',
+ '﹕' => ':',
+ '﹖' => '?',
+ '﹗' => '!',
+ '﹘' => '—',
+ '﹙' => '(',
+ '﹚' => ')',
+ '﹛' => '{',
+ '﹜' => '}',
+ '﹝' => '〔',
+ '﹞' => '〕',
+ '﹟' => '#',
+ '﹠' => '&',
+ '﹡' => '*',
+ '﹢' => '+',
+ '﹣' => '-',
+ '﹤' => '<',
+ '﹥' => '>',
+ '﹦' => '=',
+ '﹨' => '\\',
+ '﹩' => '$',
+ '﹪' => '%',
+ '﹫' => '@',
+ 'ﹰ' => ' ً',
+ 'ﹱ' => 'ـً',
+ 'ﹲ' => ' ٌ',
+ 'ﹴ' => ' ٍ',
+ 'ﹶ' => ' َ',
+ 'ﹷ' => 'ـَ',
+ 'ﹸ' => ' ُ',
+ 'ﹹ' => 'ـُ',
+ 'ﹺ' => ' ِ',
+ 'ﹻ' => 'ـِ',
+ 'ﹼ' => ' ّ',
+ 'ﹽ' => 'ـّ',
+ 'ﹾ' => ' ْ',
+ 'ﹿ' => 'ـْ',
+ 'ﺀ' => 'ء',
+ 'ﺁ' => 'آ',
+ 'ﺂ' => 'آ',
+ 'ﺃ' => 'أ',
+ 'ﺄ' => 'أ',
+ 'ﺅ' => 'ؤ',
+ 'ﺆ' => 'ؤ',
+ 'ﺇ' => 'إ',
+ 'ﺈ' => 'إ',
+ 'ﺉ' => 'ئ',
+ 'ﺊ' => 'ئ',
+ 'ﺋ' => 'ئ',
+ 'ﺌ' => 'ئ',
+ 'ﺍ' => 'ا',
+ 'ﺎ' => 'ا',
+ 'ﺏ' => 'ب',
+ 'ﺐ' => 'ب',
+ 'ﺑ' => 'ب',
+ 'ﺒ' => 'ب',
+ 'ﺓ' => 'ة',
+ 'ﺔ' => 'ة',
+ 'ﺕ' => 'ت',
+ 'ﺖ' => 'ت',
+ 'ﺗ' => 'ت',
+ 'ﺘ' => 'ت',
+ 'ﺙ' => 'ث',
+ 'ﺚ' => 'ث',
+ 'ﺛ' => 'ث',
+ 'ﺜ' => 'ث',
+ 'ﺝ' => 'ج',
+ 'ﺞ' => 'ج',
+ 'ﺟ' => 'ج',
+ 'ﺠ' => 'ج',
+ 'ﺡ' => 'ح',
+ 'ﺢ' => 'ح',
+ 'ﺣ' => 'ح',
+ 'ﺤ' => 'ح',
+ 'ﺥ' => 'خ',
+ 'ﺦ' => 'خ',
+ 'ﺧ' => 'خ',
+ 'ﺨ' => 'خ',
+ 'ﺩ' => 'د',
+ 'ﺪ' => 'د',
+ 'ﺫ' => 'ذ',
+ 'ﺬ' => 'ذ',
+ 'ﺭ' => 'ر',
+ 'ﺮ' => 'ر',
+ 'ﺯ' => 'ز',
+ 'ﺰ' => 'ز',
+ 'ﺱ' => 'س',
+ 'ﺲ' => 'س',
+ 'ﺳ' => 'س',
+ 'ﺴ' => 'س',
+ 'ﺵ' => 'ش',
+ 'ﺶ' => 'ش',
+ 'ﺷ' => 'ش',
+ 'ﺸ' => 'ش',
+ 'ﺹ' => 'ص',
+ 'ﺺ' => 'ص',
+ 'ﺻ' => 'ص',
+ 'ﺼ' => 'ص',
+ 'ﺽ' => 'ض',
+ 'ﺾ' => 'ض',
+ 'ﺿ' => 'ض',
+ 'ﻀ' => 'ض',
+ 'ﻁ' => 'ط',
+ 'ﻂ' => 'ط',
+ 'ﻃ' => 'ط',
+ 'ﻄ' => 'ط',
+ 'ﻅ' => 'ظ',
+ 'ﻆ' => 'ظ',
+ 'ﻇ' => 'ظ',
+ 'ﻈ' => 'ظ',
+ 'ﻉ' => 'ع',
+ 'ﻊ' => 'ع',
+ 'ﻋ' => 'ع',
+ 'ﻌ' => 'ع',
+ 'ﻍ' => 'غ',
+ 'ﻎ' => 'غ',
+ 'ﻏ' => 'غ',
+ 'ﻐ' => 'غ',
+ 'ﻑ' => 'ف',
+ 'ﻒ' => 'ف',
+ 'ﻓ' => 'ف',
+ 'ﻔ' => 'ف',
+ 'ﻕ' => 'ق',
+ 'ﻖ' => 'ق',
+ 'ﻗ' => 'ق',
+ 'ﻘ' => 'ق',
+ 'ﻙ' => 'ك',
+ 'ﻚ' => 'ك',
+ 'ﻛ' => 'ك',
+ 'ﻜ' => 'ك',
+ 'ﻝ' => 'ل',
+ 'ﻞ' => 'ل',
+ 'ﻟ' => 'ل',
+ 'ﻠ' => 'ل',
+ 'ﻡ' => 'م',
+ 'ﻢ' => 'م',
+ 'ﻣ' => 'م',
+ 'ﻤ' => 'م',
+ 'ﻥ' => 'ن',
+ 'ﻦ' => 'ن',
+ 'ﻧ' => 'ن',
+ 'ﻨ' => 'ن',
+ 'ﻩ' => 'ه',
+ 'ﻪ' => 'ه',
+ 'ﻫ' => 'ه',
+ 'ﻬ' => 'ه',
+ 'ﻭ' => 'و',
+ 'ﻮ' => 'و',
+ 'ﻯ' => 'ى',
+ 'ﻰ' => 'ى',
+ 'ﻱ' => 'ي',
+ 'ﻲ' => 'ي',
+ 'ﻳ' => 'ي',
+ 'ﻴ' => 'ي',
+ 'ﻵ' => 'لآ',
+ 'ﻶ' => 'لآ',
+ 'ﻷ' => 'لأ',
+ 'ﻸ' => 'لأ',
+ 'ﻹ' => 'لإ',
+ 'ﻺ' => 'لإ',
+ 'ﻻ' => 'لا',
+ 'ﻼ' => 'لا',
+ '!' => '!',
+ '"' => '"',
+ '#' => '#',
+ '$' => '$',
+ '%' => '%',
+ '&' => '&',
+ ''' => '\'',
+ '(' => '(',
+ ')' => ')',
+ '*' => '*',
+ '+' => '+',
+ ',' => ',',
+ '-' => '-',
+ '.' => '.',
+ '/' => '/',
+ '0' => '0',
+ '1' => '1',
+ '2' => '2',
+ '3' => '3',
+ '4' => '4',
+ '5' => '5',
+ '6' => '6',
+ '7' => '7',
+ '8' => '8',
+ '9' => '9',
+ ':' => ':',
+ ';' => ';',
+ '<' => '<',
+ '=' => '=',
+ '>' => '>',
+ '?' => '?',
+ '@' => '@',
+ 'A' => 'A',
+ 'B' => 'B',
+ 'C' => 'C',
+ 'D' => 'D',
+ 'E' => 'E',
+ 'F' => 'F',
+ 'G' => 'G',
+ 'H' => 'H',
+ 'I' => 'I',
+ 'J' => 'J',
+ 'K' => 'K',
+ 'L' => 'L',
+ 'M' => 'M',
+ 'N' => 'N',
+ 'O' => 'O',
+ 'P' => 'P',
+ 'Q' => 'Q',
+ 'R' => 'R',
+ 'S' => 'S',
+ 'T' => 'T',
+ 'U' => 'U',
+ 'V' => 'V',
+ 'W' => 'W',
+ 'X' => 'X',
+ 'Y' => 'Y',
+ 'Z' => 'Z',
+ '[' => '[',
+ '\' => '\\',
+ ']' => ']',
+ '^' => '^',
+ '_' => '_',
+ '`' => '`',
+ 'a' => 'a',
+ 'b' => 'b',
+ 'c' => 'c',
+ 'd' => 'd',
+ 'e' => 'e',
+ 'f' => 'f',
+ 'g' => 'g',
+ 'h' => 'h',
+ 'i' => 'i',
+ 'j' => 'j',
+ 'k' => 'k',
+ 'l' => 'l',
+ 'm' => 'm',
+ 'n' => 'n',
+ 'o' => 'o',
+ 'p' => 'p',
+ 'q' => 'q',
+ 'r' => 'r',
+ 's' => 's',
+ 't' => 't',
+ 'u' => 'u',
+ 'v' => 'v',
+ 'w' => 'w',
+ 'x' => 'x',
+ 'y' => 'y',
+ 'z' => 'z',
+ '{' => '{',
+ '|' => '|',
+ '}' => '}',
+ '~' => '~',
+ '⦅' => '⦅',
+ '⦆' => '⦆',
+ '。' => '。',
+ '「' => '「',
+ '」' => '」',
+ '、' => '、',
+ '・' => '・',
+ 'ヲ' => 'ヲ',
+ 'ァ' => 'ァ',
+ 'ィ' => 'ィ',
+ 'ゥ' => 'ゥ',
+ 'ェ' => 'ェ',
+ 'ォ' => 'ォ',
+ 'ャ' => 'ャ',
+ 'ュ' => 'ュ',
+ 'ョ' => 'ョ',
+ 'ッ' => 'ッ',
+ 'ー' => 'ー',
+ 'ア' => 'ア',
+ 'イ' => 'イ',
+ 'ウ' => 'ウ',
+ 'エ' => 'エ',
+ 'オ' => 'オ',
+ 'カ' => 'カ',
+ 'キ' => 'キ',
+ 'ク' => 'ク',
+ 'ケ' => 'ケ',
+ 'コ' => 'コ',
+ 'サ' => 'サ',
+ 'シ' => 'シ',
+ 'ス' => 'ス',
+ 'セ' => 'セ',
+ 'ソ' => 'ソ',
+ 'タ' => 'タ',
+ 'チ' => 'チ',
+ 'ツ' => 'ツ',
+ 'テ' => 'テ',
+ 'ト' => 'ト',
+ 'ナ' => 'ナ',
+ 'ニ' => 'ニ',
+ 'ヌ' => 'ヌ',
+ 'ネ' => 'ネ',
+ 'ノ' => 'ノ',
+ 'ハ' => 'ハ',
+ 'ヒ' => 'ヒ',
+ 'フ' => 'フ',
+ 'ヘ' => 'ヘ',
+ 'ホ' => 'ホ',
+ 'マ' => 'マ',
+ 'ミ' => 'ミ',
+ 'ム' => 'ム',
+ 'メ' => 'メ',
+ 'モ' => 'モ',
+ 'ヤ' => 'ヤ',
+ 'ユ' => 'ユ',
+ 'ヨ' => 'ヨ',
+ 'ラ' => 'ラ',
+ 'リ' => 'リ',
+ 'ル' => 'ル',
+ 'レ' => 'レ',
+ 'ロ' => 'ロ',
+ 'ワ' => 'ワ',
+ 'ン' => 'ン',
+ '゙' => '゙',
+ '゚' => '゚',
+ 'ᅠ' => 'ᅠ',
+ 'ᄀ' => 'ᄀ',
+ 'ᄁ' => 'ᄁ',
+ 'ᆪ' => 'ᆪ',
+ 'ᄂ' => 'ᄂ',
+ 'ᆬ' => 'ᆬ',
+ 'ᆭ' => 'ᆭ',
+ 'ᄃ' => 'ᄃ',
+ 'ᄄ' => 'ᄄ',
+ 'ᄅ' => 'ᄅ',
+ 'ᆰ' => 'ᆰ',
+ 'ᆱ' => 'ᆱ',
+ 'ᆲ' => 'ᆲ',
+ 'ᆳ' => 'ᆳ',
+ 'ᆴ' => 'ᆴ',
+ 'ᆵ' => 'ᆵ',
+ 'ᄚ' => 'ᄚ',
+ 'ᄆ' => 'ᄆ',
+ 'ᄇ' => 'ᄇ',
+ 'ᄈ' => 'ᄈ',
+ 'ᄡ' => 'ᄡ',
+ 'ᄉ' => 'ᄉ',
+ 'ᄊ' => 'ᄊ',
+ 'ᄋ' => 'ᄋ',
+ 'ᄌ' => 'ᄌ',
+ 'ᄍ' => 'ᄍ',
+ 'ᄎ' => 'ᄎ',
+ 'ᄏ' => 'ᄏ',
+ 'ᄐ' => 'ᄐ',
+ 'ᄑ' => 'ᄑ',
+ 'ᄒ' => 'ᄒ',
+ 'ᅡ' => 'ᅡ',
+ 'ᅢ' => 'ᅢ',
+ 'ᅣ' => 'ᅣ',
+ 'ᅤ' => 'ᅤ',
+ 'ᅥ' => 'ᅥ',
+ 'ᅦ' => 'ᅦ',
+ 'ᅧ' => 'ᅧ',
+ 'ᅨ' => 'ᅨ',
+ 'ᅩ' => 'ᅩ',
+ 'ᅪ' => 'ᅪ',
+ 'ᅫ' => 'ᅫ',
+ 'ᅬ' => 'ᅬ',
+ 'ᅭ' => 'ᅭ',
+ 'ᅮ' => 'ᅮ',
+ 'ᅯ' => 'ᅯ',
+ 'ᅰ' => 'ᅰ',
+ 'ᅱ' => 'ᅱ',
+ 'ᅲ' => 'ᅲ',
+ 'ᅳ' => 'ᅳ',
+ 'ᅴ' => 'ᅴ',
+ 'ᅵ' => 'ᅵ',
+ '¢' => '¢',
+ '£' => '£',
+ '¬' => '¬',
+ ' ̄' => ' ̄',
+ '¦' => '¦',
+ '¥' => '¥',
+ '₩' => '₩',
+ '│' => '│',
+ '←' => '←',
+ '↑' => '↑',
+ '→' => '→',
+ '↓' => '↓',
+ '■' => '■',
+ '○' => '○',
+ '𝐀' => 'A',
+ '𝐁' => 'B',
+ '𝐂' => 'C',
+ '𝐃' => 'D',
+ '𝐄' => 'E',
+ '𝐅' => 'F',
+ '𝐆' => 'G',
+ '𝐇' => 'H',
+ '𝐈' => 'I',
+ '𝐉' => 'J',
+ '𝐊' => 'K',
+ '𝐋' => 'L',
+ '𝐌' => 'M',
+ '𝐍' => 'N',
+ '𝐎' => 'O',
+ '𝐏' => 'P',
+ '𝐐' => 'Q',
+ '𝐑' => 'R',
+ '𝐒' => 'S',
+ '𝐓' => 'T',
+ '𝐔' => 'U',
+ '𝐕' => 'V',
+ '𝐖' => 'W',
+ '𝐗' => 'X',
+ '𝐘' => 'Y',
+ '𝐙' => 'Z',
+ '𝐚' => 'a',
+ '𝐛' => 'b',
+ '𝐜' => 'c',
+ '𝐝' => 'd',
+ '𝐞' => 'e',
+ '𝐟' => 'f',
+ '𝐠' => 'g',
+ '𝐡' => 'h',
+ '𝐢' => 'i',
+ '𝐣' => 'j',
+ '𝐤' => 'k',
+ '𝐥' => 'l',
+ '𝐦' => 'm',
+ '𝐧' => 'n',
+ '𝐨' => 'o',
+ '𝐩' => 'p',
+ '𝐪' => 'q',
+ '𝐫' => 'r',
+ '𝐬' => 's',
+ '𝐭' => 't',
+ '𝐮' => 'u',
+ '𝐯' => 'v',
+ '𝐰' => 'w',
+ '𝐱' => 'x',
+ '𝐲' => 'y',
+ '𝐳' => 'z',
+ '𝐴' => 'A',
+ '𝐵' => 'B',
+ '𝐶' => 'C',
+ '𝐷' => 'D',
+ '𝐸' => 'E',
+ '𝐹' => 'F',
+ '𝐺' => 'G',
+ '𝐻' => 'H',
+ '𝐼' => 'I',
+ '𝐽' => 'J',
+ '𝐾' => 'K',
+ '𝐿' => 'L',
+ '𝑀' => 'M',
+ '𝑁' => 'N',
+ '𝑂' => 'O',
+ '𝑃' => 'P',
+ '𝑄' => 'Q',
+ '𝑅' => 'R',
+ '𝑆' => 'S',
+ '𝑇' => 'T',
+ '𝑈' => 'U',
+ '𝑉' => 'V',
+ '𝑊' => 'W',
+ '𝑋' => 'X',
+ '𝑌' => 'Y',
+ '𝑍' => 'Z',
+ '𝑎' => 'a',
+ '𝑏' => 'b',
+ '𝑐' => 'c',
+ '𝑑' => 'd',
+ '𝑒' => 'e',
+ '𝑓' => 'f',
+ '𝑔' => 'g',
+ '𝑖' => 'i',
+ '𝑗' => 'j',
+ '𝑘' => 'k',
+ '𝑙' => 'l',
+ '𝑚' => 'm',
+ '𝑛' => 'n',
+ '𝑜' => 'o',
+ '𝑝' => 'p',
+ '𝑞' => 'q',
+ '𝑟' => 'r',
+ '𝑠' => 's',
+ '𝑡' => 't',
+ '𝑢' => 'u',
+ '𝑣' => 'v',
+ '𝑤' => 'w',
+ '𝑥' => 'x',
+ '𝑦' => 'y',
+ '𝑧' => 'z',
+ '𝑨' => 'A',
+ '𝑩' => 'B',
+ '𝑪' => 'C',
+ '𝑫' => 'D',
+ '𝑬' => 'E',
+ '𝑭' => 'F',
+ '𝑮' => 'G',
+ '𝑯' => 'H',
+ '𝑰' => 'I',
+ '𝑱' => 'J',
+ '𝑲' => 'K',
+ '𝑳' => 'L',
+ '𝑴' => 'M',
+ '𝑵' => 'N',
+ '𝑶' => 'O',
+ '𝑷' => 'P',
+ '𝑸' => 'Q',
+ '𝑹' => 'R',
+ '𝑺' => 'S',
+ '𝑻' => 'T',
+ '𝑼' => 'U',
+ '𝑽' => 'V',
+ '𝑾' => 'W',
+ '𝑿' => 'X',
+ '𝒀' => 'Y',
+ '𝒁' => 'Z',
+ '𝒂' => 'a',
+ '𝒃' => 'b',
+ '𝒄' => 'c',
+ '𝒅' => 'd',
+ '𝒆' => 'e',
+ '𝒇' => 'f',
+ '𝒈' => 'g',
+ '𝒉' => 'h',
+ '𝒊' => 'i',
+ '𝒋' => 'j',
+ '𝒌' => 'k',
+ '𝒍' => 'l',
+ '𝒎' => 'm',
+ '𝒏' => 'n',
+ '𝒐' => 'o',
+ '𝒑' => 'p',
+ '𝒒' => 'q',
+ '𝒓' => 'r',
+ '𝒔' => 's',
+ '𝒕' => 't',
+ '𝒖' => 'u',
+ '𝒗' => 'v',
+ '𝒘' => 'w',
+ '𝒙' => 'x',
+ '𝒚' => 'y',
+ '𝒛' => 'z',
+ '𝒜' => 'A',
+ '𝒞' => 'C',
+ '𝒟' => 'D',
+ '𝒢' => 'G',
+ '𝒥' => 'J',
+ '𝒦' => 'K',
+ '𝒩' => 'N',
+ '𝒪' => 'O',
+ '𝒫' => 'P',
+ '𝒬' => 'Q',
+ '𝒮' => 'S',
+ '𝒯' => 'T',
+ '𝒰' => 'U',
+ '𝒱' => 'V',
+ '𝒲' => 'W',
+ '𝒳' => 'X',
+ '𝒴' => 'Y',
+ '𝒵' => 'Z',
+ '𝒶' => 'a',
+ '𝒷' => 'b',
+ '𝒸' => 'c',
+ '𝒹' => 'd',
+ '𝒻' => 'f',
+ '𝒽' => 'h',
+ '𝒾' => 'i',
+ '𝒿' => 'j',
+ '𝓀' => 'k',
+ '𝓁' => 'l',
+ '𝓂' => 'm',
+ '𝓃' => 'n',
+ '𝓅' => 'p',
+ '𝓆' => 'q',
+ '𝓇' => 'r',
+ '𝓈' => 's',
+ '𝓉' => 't',
+ '𝓊' => 'u',
+ '𝓋' => 'v',
+ '𝓌' => 'w',
+ '𝓍' => 'x',
+ '𝓎' => 'y',
+ '𝓏' => 'z',
+ '𝓐' => 'A',
+ '𝓑' => 'B',
+ '𝓒' => 'C',
+ '𝓓' => 'D',
+ '𝓔' => 'E',
+ '𝓕' => 'F',
+ '𝓖' => 'G',
+ '𝓗' => 'H',
+ '𝓘' => 'I',
+ '𝓙' => 'J',
+ '𝓚' => 'K',
+ '𝓛' => 'L',
+ '𝓜' => 'M',
+ '𝓝' => 'N',
+ '𝓞' => 'O',
+ '𝓟' => 'P',
+ '𝓠' => 'Q',
+ '𝓡' => 'R',
+ '𝓢' => 'S',
+ '𝓣' => 'T',
+ '𝓤' => 'U',
+ '𝓥' => 'V',
+ '𝓦' => 'W',
+ '𝓧' => 'X',
+ '𝓨' => 'Y',
+ '𝓩' => 'Z',
+ '𝓪' => 'a',
+ '𝓫' => 'b',
+ '𝓬' => 'c',
+ '𝓭' => 'd',
+ '𝓮' => 'e',
+ '𝓯' => 'f',
+ '𝓰' => 'g',
+ '𝓱' => 'h',
+ '𝓲' => 'i',
+ '𝓳' => 'j',
+ '𝓴' => 'k',
+ '𝓵' => 'l',
+ '𝓶' => 'm',
+ '𝓷' => 'n',
+ '𝓸' => 'o',
+ '𝓹' => 'p',
+ '𝓺' => 'q',
+ '𝓻' => 'r',
+ '𝓼' => 's',
+ '𝓽' => 't',
+ '𝓾' => 'u',
+ '𝓿' => 'v',
+ '𝔀' => 'w',
+ '𝔁' => 'x',
+ '𝔂' => 'y',
+ '𝔃' => 'z',
+ '𝔄' => 'A',
+ '𝔅' => 'B',
+ '𝔇' => 'D',
+ '𝔈' => 'E',
+ '𝔉' => 'F',
+ '𝔊' => 'G',
+ '𝔍' => 'J',
+ '𝔎' => 'K',
+ '𝔏' => 'L',
+ '𝔐' => 'M',
+ '𝔑' => 'N',
+ '𝔒' => 'O',
+ '𝔓' => 'P',
+ '𝔔' => 'Q',
+ '𝔖' => 'S',
+ '𝔗' => 'T',
+ '𝔘' => 'U',
+ '𝔙' => 'V',
+ '𝔚' => 'W',
+ '𝔛' => 'X',
+ '𝔜' => 'Y',
+ '𝔞' => 'a',
+ '𝔟' => 'b',
+ '𝔠' => 'c',
+ '𝔡' => 'd',
+ '𝔢' => 'e',
+ '𝔣' => 'f',
+ '𝔤' => 'g',
+ '𝔥' => 'h',
+ '𝔦' => 'i',
+ '𝔧' => 'j',
+ '𝔨' => 'k',
+ '𝔩' => 'l',
+ '𝔪' => 'm',
+ '𝔫' => 'n',
+ '𝔬' => 'o',
+ '𝔭' => 'p',
+ '𝔮' => 'q',
+ '𝔯' => 'r',
+ '𝔰' => 's',
+ '𝔱' => 't',
+ '𝔲' => 'u',
+ '𝔳' => 'v',
+ '𝔴' => 'w',
+ '𝔵' => 'x',
+ '𝔶' => 'y',
+ '𝔷' => 'z',
+ '𝔸' => 'A',
+ '𝔹' => 'B',
+ '𝔻' => 'D',
+ '𝔼' => 'E',
+ '𝔽' => 'F',
+ '𝔾' => 'G',
+ '𝕀' => 'I',
+ '𝕁' => 'J',
+ '𝕂' => 'K',
+ '𝕃' => 'L',
+ '𝕄' => 'M',
+ '𝕆' => 'O',
+ '𝕊' => 'S',
+ '𝕋' => 'T',
+ '𝕌' => 'U',
+ '𝕍' => 'V',
+ '𝕎' => 'W',
+ '𝕏' => 'X',
+ '𝕐' => 'Y',
+ '𝕒' => 'a',
+ '𝕓' => 'b',
+ '𝕔' => 'c',
+ '𝕕' => 'd',
+ '𝕖' => 'e',
+ '𝕗' => 'f',
+ '𝕘' => 'g',
+ '𝕙' => 'h',
+ '𝕚' => 'i',
+ '𝕛' => 'j',
+ '𝕜' => 'k',
+ '𝕝' => 'l',
+ '𝕞' => 'm',
+ '𝕟' => 'n',
+ '𝕠' => 'o',
+ '𝕡' => 'p',
+ '𝕢' => 'q',
+ '𝕣' => 'r',
+ '𝕤' => 's',
+ '𝕥' => 't',
+ '𝕦' => 'u',
+ '𝕧' => 'v',
+ '𝕨' => 'w',
+ '𝕩' => 'x',
+ '𝕪' => 'y',
+ '𝕫' => 'z',
+ '𝕬' => 'A',
+ '𝕭' => 'B',
+ '𝕮' => 'C',
+ '𝕯' => 'D',
+ '𝕰' => 'E',
+ '𝕱' => 'F',
+ '𝕲' => 'G',
+ '𝕳' => 'H',
+ '𝕴' => 'I',
+ '𝕵' => 'J',
+ '𝕶' => 'K',
+ '𝕷' => 'L',
+ '𝕸' => 'M',
+ '𝕹' => 'N',
+ '𝕺' => 'O',
+ '𝕻' => 'P',
+ '𝕼' => 'Q',
+ '𝕽' => 'R',
+ '𝕾' => 'S',
+ '𝕿' => 'T',
+ '𝖀' => 'U',
+ '𝖁' => 'V',
+ '𝖂' => 'W',
+ '𝖃' => 'X',
+ '𝖄' => 'Y',
+ '𝖅' => 'Z',
+ '𝖆' => 'a',
+ '𝖇' => 'b',
+ '𝖈' => 'c',
+ '𝖉' => 'd',
+ '𝖊' => 'e',
+ '𝖋' => 'f',
+ '𝖌' => 'g',
+ '𝖍' => 'h',
+ '𝖎' => 'i',
+ '𝖏' => 'j',
+ '𝖐' => 'k',
+ '𝖑' => 'l',
+ '𝖒' => 'm',
+ '𝖓' => 'n',
+ '𝖔' => 'o',
+ '𝖕' => 'p',
+ '𝖖' => 'q',
+ '𝖗' => 'r',
+ '𝖘' => 's',
+ '𝖙' => 't',
+ '𝖚' => 'u',
+ '𝖛' => 'v',
+ '𝖜' => 'w',
+ '𝖝' => 'x',
+ '𝖞' => 'y',
+ '𝖟' => 'z',
+ '𝖠' => 'A',
+ '𝖡' => 'B',
+ '𝖢' => 'C',
+ '𝖣' => 'D',
+ '𝖤' => 'E',
+ '𝖥' => 'F',
+ '𝖦' => 'G',
+ '𝖧' => 'H',
+ '𝖨' => 'I',
+ '𝖩' => 'J',
+ '𝖪' => 'K',
+ '𝖫' => 'L',
+ '𝖬' => 'M',
+ '𝖭' => 'N',
+ '𝖮' => 'O',
+ '𝖯' => 'P',
+ '𝖰' => 'Q',
+ '𝖱' => 'R',
+ '𝖲' => 'S',
+ '𝖳' => 'T',
+ '𝖴' => 'U',
+ '𝖵' => 'V',
+ '𝖶' => 'W',
+ '𝖷' => 'X',
+ '𝖸' => 'Y',
+ '𝖹' => 'Z',
+ '𝖺' => 'a',
+ '𝖻' => 'b',
+ '𝖼' => 'c',
+ '𝖽' => 'd',
+ '𝖾' => 'e',
+ '𝖿' => 'f',
+ '𝗀' => 'g',
+ '𝗁' => 'h',
+ '𝗂' => 'i',
+ '𝗃' => 'j',
+ '𝗄' => 'k',
+ '𝗅' => 'l',
+ '𝗆' => 'm',
+ '𝗇' => 'n',
+ '𝗈' => 'o',
+ '𝗉' => 'p',
+ '𝗊' => 'q',
+ '𝗋' => 'r',
+ '𝗌' => 's',
+ '𝗍' => 't',
+ '𝗎' => 'u',
+ '𝗏' => 'v',
+ '𝗐' => 'w',
+ '𝗑' => 'x',
+ '𝗒' => 'y',
+ '𝗓' => 'z',
+ '𝗔' => 'A',
+ '𝗕' => 'B',
+ '𝗖' => 'C',
+ '𝗗' => 'D',
+ '𝗘' => 'E',
+ '𝗙' => 'F',
+ '𝗚' => 'G',
+ '𝗛' => 'H',
+ '𝗜' => 'I',
+ '𝗝' => 'J',
+ '𝗞' => 'K',
+ '𝗟' => 'L',
+ '𝗠' => 'M',
+ '𝗡' => 'N',
+ '𝗢' => 'O',
+ '𝗣' => 'P',
+ '𝗤' => 'Q',
+ '𝗥' => 'R',
+ '𝗦' => 'S',
+ '𝗧' => 'T',
+ '𝗨' => 'U',
+ '𝗩' => 'V',
+ '𝗪' => 'W',
+ '𝗫' => 'X',
+ '𝗬' => 'Y',
+ '𝗭' => 'Z',
+ '𝗮' => 'a',
+ '𝗯' => 'b',
+ '𝗰' => 'c',
+ '𝗱' => 'd',
+ '𝗲' => 'e',
+ '𝗳' => 'f',
+ '𝗴' => 'g',
+ '𝗵' => 'h',
+ '𝗶' => 'i',
+ '𝗷' => 'j',
+ '𝗸' => 'k',
+ '𝗹' => 'l',
+ '𝗺' => 'm',
+ '𝗻' => 'n',
+ '𝗼' => 'o',
+ '𝗽' => 'p',
+ '𝗾' => 'q',
+ '𝗿' => 'r',
+ '𝘀' => 's',
+ '𝘁' => 't',
+ '𝘂' => 'u',
+ '𝘃' => 'v',
+ '𝘄' => 'w',
+ '𝘅' => 'x',
+ '𝘆' => 'y',
+ '𝘇' => 'z',
+ '𝘈' => 'A',
+ '𝘉' => 'B',
+ '𝘊' => 'C',
+ '𝘋' => 'D',
+ '𝘌' => 'E',
+ '𝘍' => 'F',
+ '𝘎' => 'G',
+ '𝘏' => 'H',
+ '𝘐' => 'I',
+ '𝘑' => 'J',
+ '𝘒' => 'K',
+ '𝘓' => 'L',
+ '𝘔' => 'M',
+ '𝘕' => 'N',
+ '𝘖' => 'O',
+ '𝘗' => 'P',
+ '𝘘' => 'Q',
+ '𝘙' => 'R',
+ '𝘚' => 'S',
+ '𝘛' => 'T',
+ '𝘜' => 'U',
+ '𝘝' => 'V',
+ '𝘞' => 'W',
+ '𝘟' => 'X',
+ '𝘠' => 'Y',
+ '𝘡' => 'Z',
+ '𝘢' => 'a',
+ '𝘣' => 'b',
+ '𝘤' => 'c',
+ '𝘥' => 'd',
+ '𝘦' => 'e',
+ '𝘧' => 'f',
+ '𝘨' => 'g',
+ '𝘩' => 'h',
+ '𝘪' => 'i',
+ '𝘫' => 'j',
+ '𝘬' => 'k',
+ '𝘭' => 'l',
+ '𝘮' => 'm',
+ '𝘯' => 'n',
+ '𝘰' => 'o',
+ '𝘱' => 'p',
+ '𝘲' => 'q',
+ '𝘳' => 'r',
+ '𝘴' => 's',
+ '𝘵' => 't',
+ '𝘶' => 'u',
+ '𝘷' => 'v',
+ '𝘸' => 'w',
+ '𝘹' => 'x',
+ '𝘺' => 'y',
+ '𝘻' => 'z',
+ '𝘼' => 'A',
+ '𝘽' => 'B',
+ '𝘾' => 'C',
+ '𝘿' => 'D',
+ '𝙀' => 'E',
+ '𝙁' => 'F',
+ '𝙂' => 'G',
+ '𝙃' => 'H',
+ '𝙄' => 'I',
+ '𝙅' => 'J',
+ '𝙆' => 'K',
+ '𝙇' => 'L',
+ '𝙈' => 'M',
+ '𝙉' => 'N',
+ '𝙊' => 'O',
+ '𝙋' => 'P',
+ '𝙌' => 'Q',
+ '𝙍' => 'R',
+ '𝙎' => 'S',
+ '𝙏' => 'T',
+ '𝙐' => 'U',
+ '𝙑' => 'V',
+ '𝙒' => 'W',
+ '𝙓' => 'X',
+ '𝙔' => 'Y',
+ '𝙕' => 'Z',
+ '𝙖' => 'a',
+ '𝙗' => 'b',
+ '𝙘' => 'c',
+ '𝙙' => 'd',
+ '𝙚' => 'e',
+ '𝙛' => 'f',
+ '𝙜' => 'g',
+ '𝙝' => 'h',
+ '𝙞' => 'i',
+ '𝙟' => 'j',
+ '𝙠' => 'k',
+ '𝙡' => 'l',
+ '𝙢' => 'm',
+ '𝙣' => 'n',
+ '𝙤' => 'o',
+ '𝙥' => 'p',
+ '𝙦' => 'q',
+ '𝙧' => 'r',
+ '𝙨' => 's',
+ '𝙩' => 't',
+ '𝙪' => 'u',
+ '𝙫' => 'v',
+ '𝙬' => 'w',
+ '𝙭' => 'x',
+ '𝙮' => 'y',
+ '𝙯' => 'z',
+ '𝙰' => 'A',
+ '𝙱' => 'B',
+ '𝙲' => 'C',
+ '𝙳' => 'D',
+ '𝙴' => 'E',
+ '𝙵' => 'F',
+ '𝙶' => 'G',
+ '𝙷' => 'H',
+ '𝙸' => 'I',
+ '𝙹' => 'J',
+ '𝙺' => 'K',
+ '𝙻' => 'L',
+ '𝙼' => 'M',
+ '𝙽' => 'N',
+ '𝙾' => 'O',
+ '𝙿' => 'P',
+ '𝚀' => 'Q',
+ '𝚁' => 'R',
+ '𝚂' => 'S',
+ '𝚃' => 'T',
+ '𝚄' => 'U',
+ '𝚅' => 'V',
+ '𝚆' => 'W',
+ '𝚇' => 'X',
+ '𝚈' => 'Y',
+ '𝚉' => 'Z',
+ '𝚊' => 'a',
+ '𝚋' => 'b',
+ '𝚌' => 'c',
+ '𝚍' => 'd',
+ '𝚎' => 'e',
+ '𝚏' => 'f',
+ '𝚐' => 'g',
+ '𝚑' => 'h',
+ '𝚒' => 'i',
+ '𝚓' => 'j',
+ '𝚔' => 'k',
+ '𝚕' => 'l',
+ '𝚖' => 'm',
+ '𝚗' => 'n',
+ '𝚘' => 'o',
+ '𝚙' => 'p',
+ '𝚚' => 'q',
+ '𝚛' => 'r',
+ '𝚜' => 's',
+ '𝚝' => 't',
+ '𝚞' => 'u',
+ '𝚟' => 'v',
+ '𝚠' => 'w',
+ '𝚡' => 'x',
+ '𝚢' => 'y',
+ '𝚣' => 'z',
+ '𝚤' => 'ı',
+ '𝚥' => 'ȷ',
+ '𝚨' => 'Α',
+ '𝚩' => 'Β',
+ '𝚪' => 'Γ',
+ '𝚫' => 'Δ',
+ '𝚬' => 'Ε',
+ '𝚭' => 'Ζ',
+ '𝚮' => 'Η',
+ '𝚯' => 'Θ',
+ '𝚰' => 'Ι',
+ '𝚱' => 'Κ',
+ '𝚲' => 'Λ',
+ '𝚳' => 'Μ',
+ '𝚴' => 'Ν',
+ '𝚵' => 'Ξ',
+ '𝚶' => 'Ο',
+ '𝚷' => 'Π',
+ '𝚸' => 'Ρ',
+ '𝚹' => 'Θ',
+ '𝚺' => 'Σ',
+ '𝚻' => 'Τ',
+ '𝚼' => 'Υ',
+ '𝚽' => 'Φ',
+ '𝚾' => 'Χ',
+ '𝚿' => 'Ψ',
+ '𝛀' => 'Ω',
+ '𝛁' => '∇',
+ '𝛂' => 'α',
+ '𝛃' => 'β',
+ '𝛄' => 'γ',
+ '𝛅' => 'δ',
+ '𝛆' => 'ε',
+ '𝛇' => 'ζ',
+ '𝛈' => 'η',
+ '𝛉' => 'θ',
+ '𝛊' => 'ι',
+ '𝛋' => 'κ',
+ '𝛌' => 'λ',
+ '𝛍' => 'μ',
+ '𝛎' => 'ν',
+ '𝛏' => 'ξ',
+ '𝛐' => 'ο',
+ '𝛑' => 'π',
+ '𝛒' => 'ρ',
+ '𝛓' => 'ς',
+ '𝛔' => 'σ',
+ '𝛕' => 'τ',
+ '𝛖' => 'υ',
+ '𝛗' => 'φ',
+ '𝛘' => 'χ',
+ '𝛙' => 'ψ',
+ '𝛚' => 'ω',
+ '𝛛' => '∂',
+ '𝛜' => 'ε',
+ '𝛝' => 'θ',
+ '𝛞' => 'κ',
+ '𝛟' => 'φ',
+ '𝛠' => 'ρ',
+ '𝛡' => 'π',
+ '𝛢' => 'Α',
+ '𝛣' => 'Β',
+ '𝛤' => 'Γ',
+ '𝛥' => 'Δ',
+ '𝛦' => 'Ε',
+ '𝛧' => 'Ζ',
+ '𝛨' => 'Η',
+ '𝛩' => 'Θ',
+ '𝛪' => 'Ι',
+ '𝛫' => 'Κ',
+ '𝛬' => 'Λ',
+ '𝛭' => 'Μ',
+ '𝛮' => 'Ν',
+ '𝛯' => 'Ξ',
+ '𝛰' => 'Ο',
+ '𝛱' => 'Π',
+ '𝛲' => 'Ρ',
+ '𝛳' => 'Θ',
+ '𝛴' => 'Σ',
+ '𝛵' => 'Τ',
+ '𝛶' => 'Υ',
+ '𝛷' => 'Φ',
+ '𝛸' => 'Χ',
+ '𝛹' => 'Ψ',
+ '𝛺' => 'Ω',
+ '𝛻' => '∇',
+ '𝛼' => 'α',
+ '𝛽' => 'β',
+ '𝛾' => 'γ',
+ '𝛿' => 'δ',
+ '𝜀' => 'ε',
+ '𝜁' => 'ζ',
+ '𝜂' => 'η',
+ '𝜃' => 'θ',
+ '𝜄' => 'ι',
+ '𝜅' => 'κ',
+ '𝜆' => 'λ',
+ '𝜇' => 'μ',
+ '𝜈' => 'ν',
+ '𝜉' => 'ξ',
+ '𝜊' => 'ο',
+ '𝜋' => 'π',
+ '𝜌' => 'ρ',
+ '𝜍' => 'ς',
+ '𝜎' => 'σ',
+ '𝜏' => 'τ',
+ '𝜐' => 'υ',
+ '𝜑' => 'φ',
+ '𝜒' => 'χ',
+ '𝜓' => 'ψ',
+ '𝜔' => 'ω',
+ '𝜕' => '∂',
+ '𝜖' => 'ε',
+ '𝜗' => 'θ',
+ '𝜘' => 'κ',
+ '𝜙' => 'φ',
+ '𝜚' => 'ρ',
+ '𝜛' => 'π',
+ '𝜜' => 'Α',
+ '𝜝' => 'Β',
+ '𝜞' => 'Γ',
+ '𝜟' => 'Δ',
+ '𝜠' => 'Ε',
+ '𝜡' => 'Ζ',
+ '𝜢' => 'Η',
+ '𝜣' => 'Θ',
+ '𝜤' => 'Ι',
+ '𝜥' => 'Κ',
+ '𝜦' => 'Λ',
+ '𝜧' => 'Μ',
+ '𝜨' => 'Ν',
+ '𝜩' => 'Ξ',
+ '𝜪' => 'Ο',
+ '𝜫' => 'Π',
+ '𝜬' => 'Ρ',
+ '𝜭' => 'Θ',
+ '𝜮' => 'Σ',
+ '𝜯' => 'Τ',
+ '𝜰' => 'Υ',
+ '𝜱' => 'Φ',
+ '𝜲' => 'Χ',
+ '𝜳' => 'Ψ',
+ '𝜴' => 'Ω',
+ '𝜵' => '∇',
+ '𝜶' => 'α',
+ '𝜷' => 'β',
+ '𝜸' => 'γ',
+ '𝜹' => 'δ',
+ '𝜺' => 'ε',
+ '𝜻' => 'ζ',
+ '𝜼' => 'η',
+ '𝜽' => 'θ',
+ '𝜾' => 'ι',
+ '𝜿' => 'κ',
+ '𝝀' => 'λ',
+ '𝝁' => 'μ',
+ '𝝂' => 'ν',
+ '𝝃' => 'ξ',
+ '𝝄' => 'ο',
+ '𝝅' => 'π',
+ '𝝆' => 'ρ',
+ '𝝇' => 'ς',
+ '𝝈' => 'σ',
+ '𝝉' => 'τ',
+ '𝝊' => 'υ',
+ '𝝋' => 'φ',
+ '𝝌' => 'χ',
+ '𝝍' => 'ψ',
+ '𝝎' => 'ω',
+ '𝝏' => '∂',
+ '𝝐' => 'ε',
+ '𝝑' => 'θ',
+ '𝝒' => 'κ',
+ '𝝓' => 'φ',
+ '𝝔' => 'ρ',
+ '𝝕' => 'π',
+ '𝝖' => 'Α',
+ '𝝗' => 'Β',
+ '𝝘' => 'Γ',
+ '𝝙' => 'Δ',
+ '𝝚' => 'Ε',
+ '𝝛' => 'Ζ',
+ '𝝜' => 'Η',
+ '𝝝' => 'Θ',
+ '𝝞' => 'Ι',
+ '𝝟' => 'Κ',
+ '𝝠' => 'Λ',
+ '𝝡' => 'Μ',
+ '𝝢' => 'Ν',
+ '𝝣' => 'Ξ',
+ '𝝤' => 'Ο',
+ '𝝥' => 'Π',
+ '𝝦' => 'Ρ',
+ '𝝧' => 'Θ',
+ '𝝨' => 'Σ',
+ '𝝩' => 'Τ',
+ '𝝪' => 'Υ',
+ '𝝫' => 'Φ',
+ '𝝬' => 'Χ',
+ '𝝭' => 'Ψ',
+ '𝝮' => 'Ω',
+ '𝝯' => '∇',
+ '𝝰' => 'α',
+ '𝝱' => 'β',
+ '𝝲' => 'γ',
+ '𝝳' => 'δ',
+ '𝝴' => 'ε',
+ '𝝵' => 'ζ',
+ '𝝶' => 'η',
+ '𝝷' => 'θ',
+ '𝝸' => 'ι',
+ '𝝹' => 'κ',
+ '𝝺' => 'λ',
+ '𝝻' => 'μ',
+ '𝝼' => 'ν',
+ '𝝽' => 'ξ',
+ '𝝾' => 'ο',
+ '𝝿' => 'π',
+ '𝞀' => 'ρ',
+ '𝞁' => 'ς',
+ '𝞂' => 'σ',
+ '𝞃' => 'τ',
+ '𝞄' => 'υ',
+ '𝞅' => 'φ',
+ '𝞆' => 'χ',
+ '𝞇' => 'ψ',
+ '𝞈' => 'ω',
+ '𝞉' => '∂',
+ '𝞊' => 'ε',
+ '𝞋' => 'θ',
+ '𝞌' => 'κ',
+ '𝞍' => 'φ',
+ '𝞎' => 'ρ',
+ '𝞏' => 'π',
+ '𝞐' => 'Α',
+ '𝞑' => 'Β',
+ '𝞒' => 'Γ',
+ '𝞓' => 'Δ',
+ '𝞔' => 'Ε',
+ '𝞕' => 'Ζ',
+ '𝞖' => 'Η',
+ '𝞗' => 'Θ',
+ '𝞘' => 'Ι',
+ '𝞙' => 'Κ',
+ '𝞚' => 'Λ',
+ '𝞛' => 'Μ',
+ '𝞜' => 'Ν',
+ '𝞝' => 'Ξ',
+ '𝞞' => 'Ο',
+ '𝞟' => 'Π',
+ '𝞠' => 'Ρ',
+ '𝞡' => 'Θ',
+ '𝞢' => 'Σ',
+ '𝞣' => 'Τ',
+ '𝞤' => 'Υ',
+ '𝞥' => 'Φ',
+ '𝞦' => 'Χ',
+ '𝞧' => 'Ψ',
+ '𝞨' => 'Ω',
+ '𝞩' => '∇',
+ '𝞪' => 'α',
+ '𝞫' => 'β',
+ '𝞬' => 'γ',
+ '𝞭' => 'δ',
+ '𝞮' => 'ε',
+ '𝞯' => 'ζ',
+ '𝞰' => 'η',
+ '𝞱' => 'θ',
+ '𝞲' => 'ι',
+ '𝞳' => 'κ',
+ '𝞴' => 'λ',
+ '𝞵' => 'μ',
+ '𝞶' => 'ν',
+ '𝞷' => 'ξ',
+ '𝞸' => 'ο',
+ '𝞹' => 'π',
+ '𝞺' => 'ρ',
+ '𝞻' => 'ς',
+ '𝞼' => 'σ',
+ '𝞽' => 'τ',
+ '𝞾' => 'υ',
+ '𝞿' => 'φ',
+ '𝟀' => 'χ',
+ '𝟁' => 'ψ',
+ '𝟂' => 'ω',
+ '𝟃' => '∂',
+ '𝟄' => 'ε',
+ '𝟅' => 'θ',
+ '𝟆' => 'κ',
+ '𝟇' => 'φ',
+ '𝟈' => 'ρ',
+ '𝟉' => 'π',
+ '𝟊' => 'Ϝ',
+ '𝟋' => 'ϝ',
+ '𝟎' => '0',
+ '𝟏' => '1',
+ '𝟐' => '2',
+ '𝟑' => '3',
+ '𝟒' => '4',
+ '𝟓' => '5',
+ '𝟔' => '6',
+ '𝟕' => '7',
+ '𝟖' => '8',
+ '𝟗' => '9',
+ '𝟘' => '0',
+ '𝟙' => '1',
+ '𝟚' => '2',
+ '𝟛' => '3',
+ '𝟜' => '4',
+ '𝟝' => '5',
+ '𝟞' => '6',
+ '𝟟' => '7',
+ '𝟠' => '8',
+ '𝟡' => '9',
+ '𝟢' => '0',
+ '𝟣' => '1',
+ '𝟤' => '2',
+ '𝟥' => '3',
+ '𝟦' => '4',
+ '𝟧' => '5',
+ '𝟨' => '6',
+ '𝟩' => '7',
+ '𝟪' => '8',
+ '𝟫' => '9',
+ '𝟬' => '0',
+ '𝟭' => '1',
+ '𝟮' => '2',
+ '𝟯' => '3',
+ '𝟰' => '4',
+ '𝟱' => '5',
+ '𝟲' => '6',
+ '𝟳' => '7',
+ '𝟴' => '8',
+ '𝟵' => '9',
+ '𝟶' => '0',
+ '𝟷' => '1',
+ '𝟸' => '2',
+ '𝟹' => '3',
+ '𝟺' => '4',
+ '𝟻' => '5',
+ '𝟼' => '6',
+ '𝟽' => '7',
+ '𝟾' => '8',
+ '𝟿' => '9',
+ '𞸀' => 'ا',
+ '𞸁' => 'ب',
+ '𞸂' => 'ج',
+ '𞸃' => 'د',
+ '𞸅' => 'و',
+ '𞸆' => 'ز',
+ '𞸇' => 'ح',
+ '𞸈' => 'ط',
+ '𞸉' => 'ي',
+ '𞸊' => 'ك',
+ '𞸋' => 'ل',
+ '𞸌' => 'م',
+ '𞸍' => 'ن',
+ '𞸎' => 'س',
+ '𞸏' => 'ع',
+ '𞸐' => 'ف',
+ '𞸑' => 'ص',
+ '𞸒' => 'ق',
+ '𞸓' => 'ر',
+ '𞸔' => 'ش',
+ '𞸕' => 'ت',
+ '𞸖' => 'ث',
+ '𞸗' => 'خ',
+ '𞸘' => 'ذ',
+ '𞸙' => 'ض',
+ '𞸚' => 'ظ',
+ '𞸛' => 'غ',
+ '𞸜' => 'ٮ',
+ '𞸝' => 'ں',
+ '𞸞' => 'ڡ',
+ '𞸟' => 'ٯ',
+ '𞸡' => 'ب',
+ '𞸢' => 'ج',
+ '𞸤' => 'ه',
+ '𞸧' => 'ح',
+ '𞸩' => 'ي',
+ '𞸪' => 'ك',
+ '𞸫' => 'ل',
+ '𞸬' => 'م',
+ '𞸭' => 'ن',
+ '𞸮' => 'س',
+ '𞸯' => 'ع',
+ '𞸰' => 'ف',
+ '𞸱' => 'ص',
+ '𞸲' => 'ق',
+ '𞸴' => 'ش',
+ '𞸵' => 'ت',
+ '𞸶' => 'ث',
+ '𞸷' => 'خ',
+ '𞸹' => 'ض',
+ '𞸻' => 'غ',
+ '𞹂' => 'ج',
+ '𞹇' => 'ح',
+ '𞹉' => 'ي',
+ '𞹋' => 'ل',
+ '𞹍' => 'ن',
+ '𞹎' => 'س',
+ '𞹏' => 'ع',
+ '𞹑' => 'ص',
+ '𞹒' => 'ق',
+ '𞹔' => 'ش',
+ '𞹗' => 'خ',
+ '𞹙' => 'ض',
+ '𞹛' => 'غ',
+ '𞹝' => 'ں',
+ '𞹟' => 'ٯ',
+ '𞹡' => 'ب',
+ '𞹢' => 'ج',
+ '𞹤' => 'ه',
+ '𞹧' => 'ح',
+ '𞹨' => 'ط',
+ '𞹩' => 'ي',
+ '𞹪' => 'ك',
+ '𞹬' => 'م',
+ '𞹭' => 'ن',
+ '𞹮' => 'س',
+ '𞹯' => 'ع',
+ '𞹰' => 'ف',
+ '𞹱' => 'ص',
+ '𞹲' => 'ق',
+ '𞹴' => 'ش',
+ '𞹵' => 'ت',
+ '𞹶' => 'ث',
+ '𞹷' => 'خ',
+ '𞹹' => 'ض',
+ '𞹺' => 'ظ',
+ '𞹻' => 'غ',
+ '𞹼' => 'ٮ',
+ '𞹾' => 'ڡ',
+ '𞺀' => 'ا',
+ '𞺁' => 'ب',
+ '𞺂' => 'ج',
+ '𞺃' => 'د',
+ '𞺄' => 'ه',
+ '𞺅' => 'و',
+ '𞺆' => 'ز',
+ '𞺇' => 'ح',
+ '𞺈' => 'ط',
+ '𞺉' => 'ي',
+ '𞺋' => 'ل',
+ '𞺌' => 'م',
+ '𞺍' => 'ن',
+ '𞺎' => 'س',
+ '𞺏' => 'ع',
+ '𞺐' => 'ف',
+ '𞺑' => 'ص',
+ '𞺒' => 'ق',
+ '𞺓' => 'ر',
+ '𞺔' => 'ش',
+ '𞺕' => 'ت',
+ '𞺖' => 'ث',
+ '𞺗' => 'خ',
+ '𞺘' => 'ذ',
+ '𞺙' => 'ض',
+ '𞺚' => 'ظ',
+ '𞺛' => 'غ',
+ '𞺡' => 'ب',
+ '𞺢' => 'ج',
+ '𞺣' => 'د',
+ '𞺥' => 'و',
+ '𞺦' => 'ز',
+ '𞺧' => 'ح',
+ '𞺨' => 'ط',
+ '𞺩' => 'ي',
+ '𞺫' => 'ل',
+ '𞺬' => 'م',
+ '𞺭' => 'ن',
+ '𞺮' => 'س',
+ '𞺯' => 'ع',
+ '𞺰' => 'ف',
+ '𞺱' => 'ص',
+ '𞺲' => 'ق',
+ '𞺳' => 'ر',
+ '𞺴' => 'ش',
+ '𞺵' => 'ت',
+ '𞺶' => 'ث',
+ '𞺷' => 'خ',
+ '𞺸' => 'ذ',
+ '𞺹' => 'ض',
+ '𞺺' => 'ظ',
+ '𞺻' => 'غ',
+ '🄀' => '0.',
+ '🄁' => '0,',
+ '🄂' => '1,',
+ '🄃' => '2,',
+ '🄄' => '3,',
+ '🄅' => '4,',
+ '🄆' => '5,',
+ '🄇' => '6,',
+ '🄈' => '7,',
+ '🄉' => '8,',
+ '🄊' => '9,',
+ '🄐' => '(A)',
+ '🄑' => '(B)',
+ '🄒' => '(C)',
+ '🄓' => '(D)',
+ '🄔' => '(E)',
+ '🄕' => '(F)',
+ '🄖' => '(G)',
+ '🄗' => '(H)',
+ '🄘' => '(I)',
+ '🄙' => '(J)',
+ '🄚' => '(K)',
+ '🄛' => '(L)',
+ '🄜' => '(M)',
+ '🄝' => '(N)',
+ '🄞' => '(O)',
+ '🄟' => '(P)',
+ '🄠' => '(Q)',
+ '🄡' => '(R)',
+ '🄢' => '(S)',
+ '🄣' => '(T)',
+ '🄤' => '(U)',
+ '🄥' => '(V)',
+ '🄦' => '(W)',
+ '🄧' => '(X)',
+ '🄨' => '(Y)',
+ '🄩' => '(Z)',
+ '🄪' => '〔S〕',
+ '🄫' => 'C',
+ '🄬' => 'R',
+ '🄭' => 'CD',
+ '🄮' => 'WZ',
+ '🄰' => 'A',
+ '🄱' => 'B',
+ '🄲' => 'C',
+ '🄳' => 'D',
+ '🄴' => 'E',
+ '🄵' => 'F',
+ '🄶' => 'G',
+ '🄷' => 'H',
+ '🄸' => 'I',
+ '🄹' => 'J',
+ '🄺' => 'K',
+ '🄻' => 'L',
+ '🄼' => 'M',
+ '🄽' => 'N',
+ '🄾' => 'O',
+ '🄿' => 'P',
+ '🅀' => 'Q',
+ '🅁' => 'R',
+ '🅂' => 'S',
+ '🅃' => 'T',
+ '🅄' => 'U',
+ '🅅' => 'V',
+ '🅆' => 'W',
+ '🅇' => 'X',
+ '🅈' => 'Y',
+ '🅉' => 'Z',
+ '🅊' => 'HV',
+ '🅋' => 'MV',
+ '🅌' => 'SD',
+ '🅍' => 'SS',
+ '🅎' => 'PPV',
+ '🅏' => 'WC',
+ '🅪' => 'MC',
+ '🅫' => 'MD',
+ '🅬' => 'MR',
+ '🆐' => 'DJ',
+ '🈀' => 'ほか',
+ '🈁' => 'ココ',
+ '🈂' => 'サ',
+ '🈐' => '手',
+ '🈑' => '字',
+ '🈒' => '双',
+ '🈓' => 'デ',
+ '🈔' => '二',
+ '🈕' => '多',
+ '🈖' => '解',
+ '🈗' => '天',
+ '🈘' => '交',
+ '🈙' => '映',
+ '🈚' => '無',
+ '🈛' => '料',
+ '🈜' => '前',
+ '🈝' => '後',
+ '🈞' => '再',
+ '🈟' => '新',
+ '🈠' => '初',
+ '🈡' => '終',
+ '🈢' => '生',
+ '🈣' => '販',
+ '🈤' => '声',
+ '🈥' => '吹',
+ '🈦' => '演',
+ '🈧' => '投',
+ '🈨' => '捕',
+ '🈩' => '一',
+ '🈪' => '三',
+ '🈫' => '遊',
+ '🈬' => '左',
+ '🈭' => '中',
+ '🈮' => '右',
+ '🈯' => '指',
+ '🈰' => '走',
+ '🈱' => '打',
+ '🈲' => '禁',
+ '🈳' => '空',
+ '🈴' => '合',
+ '🈵' => '満',
+ '🈶' => '有',
+ '🈷' => '月',
+ '🈸' => '申',
+ '🈹' => '割',
+ '🈺' => '営',
+ '🈻' => '配',
+ '🉀' => '〔本〕',
+ '🉁' => '〔三〕',
+ '🉂' => '〔二〕',
+ '🉃' => '〔安〕',
+ '🉄' => '〔点〕',
+ '🉅' => '〔打〕',
+ '🉆' => '〔盗〕',
+ '🉇' => '〔勝〕',
+ '🉈' => '〔敗〕',
+ '🉐' => '得',
+ '🉑' => '可',
+ '🯰' => '0',
+ '🯱' => '1',
+ '🯲' => '2',
+ '🯳' => '3',
+ '🯴' => '4',
+ '🯵' => '5',
+ '🯶' => '6',
+ '🯷' => '7',
+ '🯸' => '8',
+ '🯹' => '9',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/bootstrap.php b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php
new file mode 100644
index 0000000..3608e5c
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Normalizer as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!function_exists('normalizer_is_normalized')) {
+ function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); }
+}
+if (!function_exists('normalizer_normalize')) {
+ function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php b/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php
new file mode 100644
index 0000000..e36d1a9
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Normalizer as p;
+
+if (!function_exists('normalizer_is_normalized')) {
+ function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); }
+}
+if (!function_exists('normalizer_normalize')) {
+ function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/composer.json b/vendor/symfony/polyfill-intl-normalizer/composer.json
new file mode 100644
index 0000000..eb452bf
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/composer.json
@@ -0,0 +1,39 @@
+{
+ "name": "symfony/polyfill-intl-normalizer",
+ "type": "library",
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" },
+ "files": [ "bootstrap.php" ],
+ "classmap": [ "Resources/stubs" ]
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/polyfill-php72/LICENSE b/vendor/symfony/polyfill-php72/LICENSE
new file mode 100644
index 0000000..4cd8bdd
--- /dev/null
+++ b/vendor/symfony/polyfill-php72/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-2019 Fabien Potencier
+
+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/symfony/polyfill-php72/Php72.php b/vendor/symfony/polyfill-php72/Php72.php
new file mode 100644
index 0000000..5e20d5b
--- /dev/null
+++ b/vendor/symfony/polyfill-php72/Php72.php
@@ -0,0 +1,217 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php72;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * @internal
+ */
+final class Php72
+{
+ private static $hashMask;
+
+ public static function utf8_encode($s)
+ {
+ $s .= $s;
+ $len = \strlen($s);
+
+ for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
+ switch (true) {
+ case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
+ case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
+ default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
+ }
+ }
+
+ return substr($s, 0, $j);
+ }
+
+ public static function utf8_decode($s)
+ {
+ $s = (string) $s;
+ $len = \strlen($s);
+
+ for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
+ switch ($s[$i] & "\xF0") {
+ case "\xC0":
+ case "\xD0":
+ $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
+ $s[$j] = $c < 256 ? \chr($c) : '?';
+ break;
+
+ case "\xF0":
+ ++$i;
+ // no break
+
+ case "\xE0":
+ $s[$j] = '?';
+ $i += 2;
+ break;
+
+ default:
+ $s[$j] = $s[$i];
+ }
+ }
+
+ return substr($s, 0, $j);
+ }
+
+ public static function php_os_family()
+ {
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ return 'Windows';
+ }
+
+ $map = [
+ 'Darwin' => 'Darwin',
+ 'DragonFly' => 'BSD',
+ 'FreeBSD' => 'BSD',
+ 'NetBSD' => 'BSD',
+ 'OpenBSD' => 'BSD',
+ 'Linux' => 'Linux',
+ 'SunOS' => 'Solaris',
+ ];
+
+ return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown';
+ }
+
+ public static function spl_object_id($object)
+ {
+ if (null === self::$hashMask) {
+ self::initHashMask();
+ }
+ if (null === $hash = spl_object_hash($object)) {
+ return;
+ }
+
+ // On 32-bit systems, PHP_INT_SIZE is 4,
+ return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
+ }
+
+ public static function sapi_windows_vt100_support($stream, $enable = null)
+ {
+ if (!\is_resource($stream)) {
+ trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);
+
+ return false;
+ }
+
+ $meta = stream_get_meta_data($stream);
+
+ if ('STDIO' !== $meta['stream_type']) {
+ trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING);
+
+ return false;
+ }
+
+ // We cannot actually disable vt100 support if it is set
+ if (false === $enable || !self::stream_isatty($stream)) {
+ return false;
+ }
+
+ // The native function does not apply to stdin
+ $meta = array_map('strtolower', $meta);
+ $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];
+
+ return !$stdin
+ && (false !== getenv('ANSICON')
+ || 'ON' === getenv('ConEmuANSI')
+ || 'xterm' === getenv('TERM')
+ || 'Hyper' === getenv('TERM_PROGRAM'));
+ }
+
+ public static function stream_isatty($stream)
+ {
+ if (!\is_resource($stream)) {
+ trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING);
+
+ return false;
+ }
+
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $stat = @fstat($stream);
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
+ }
+
+ return \function_exists('posix_isatty') && @posix_isatty($stream);
+ }
+
+ private static function initHashMask()
+ {
+ $obj = (object) [];
+ self::$hashMask = -1;
+
+ // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
+ $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'];
+ foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) {
+ if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
+ $frame['line'] = 0;
+ break;
+ }
+ }
+ if (!empty($frame['line'])) {
+ ob_start();
+ debug_zval_dump($obj);
+ self::$hashMask = (int) substr(ob_get_clean(), 17);
+ }
+
+ self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1)));
+ }
+
+ public static function mb_chr($code, $encoding = null)
+ {
+ if (0x80 > $code %= 0x200000) {
+ $s = \chr($code);
+ } elseif (0x800 > $code) {
+ $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
+ } elseif (0x10000 > $code) {
+ $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
+ } else {
+ $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
+ }
+
+ if ('UTF-8' !== $encoding = $encoding ?? mb_internal_encoding()) {
+ $s = mb_convert_encoding($s, $encoding, 'UTF-8');
+ }
+
+ return $s;
+ }
+
+ public static function mb_ord($s, $encoding = null)
+ {
+ if (null === $encoding) {
+ $s = mb_convert_encoding($s, 'UTF-8');
+ } elseif ('UTF-8' !== $encoding) {
+ $s = mb_convert_encoding($s, 'UTF-8', $encoding);
+ }
+
+ if (1 === \strlen($s)) {
+ return \ord($s);
+ }
+
+ $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
+ if (0xF0 <= $code) {
+ return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
+ }
+ if (0xE0 <= $code) {
+ return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
+ }
+ if (0xC0 <= $code) {
+ return (($code - 0xC0) << 6) + $s[2] - 0x80;
+ }
+
+ return $code;
+ }
+}
diff --git a/vendor/symfony/polyfill-php72/bootstrap.php b/vendor/symfony/polyfill-php72/bootstrap.php
new file mode 100644
index 0000000..b5c92d4
--- /dev/null
+++ b/vendor/symfony/polyfill-php72/bootstrap.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php72 as p;
+
+if (\PHP_VERSION_ID >= 70200) {
+ return;
+}
+
+if (!defined('PHP_FLOAT_DIG')) {
+ define('PHP_FLOAT_DIG', 15);
+}
+if (!defined('PHP_FLOAT_EPSILON')) {
+ define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
+}
+if (!defined('PHP_FLOAT_MIN')) {
+ define('PHP_FLOAT_MIN', 2.2250738585072E-308);
+}
+if (!defined('PHP_FLOAT_MAX')) {
+ define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
+}
+if (!defined('PHP_OS_FAMILY')) {
+ define('PHP_OS_FAMILY', p\Php72::php_os_family());
+}
+
+if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) {
+ function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); }
+}
+if (!function_exists('stream_isatty')) {
+ function stream_isatty($stream) { return p\Php72::stream_isatty($stream); }
+}
+if (!function_exists('utf8_encode')) {
+ function utf8_encode($string) { return p\Php72::utf8_encode($string); }
+}
+if (!function_exists('utf8_decode')) {
+ function utf8_decode($string) { return p\Php72::utf8_decode($string); }
+}
+if (!function_exists('spl_object_id')) {
+ function spl_object_id($object) { return p\Php72::spl_object_id($object); }
+}
+if (!function_exists('mb_ord')) {
+ function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); }
+}
+if (!function_exists('mb_chr')) {
+ function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); }
+}
+if (!function_exists('mb_scrub')) {
+ function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }
+}
diff --git a/vendor/symfony/polyfill-php72/composer.json b/vendor/symfony/polyfill-php72/composer.json
new file mode 100644
index 0000000..4eac690
--- /dev/null
+++ b/vendor/symfony/polyfill-php72/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "symfony/polyfill-php72",
+ "type": "library",
+ "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Php72\\": "" },
+ "files": [ "bootstrap.php" ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}