summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-09-18 03:49:17 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-09-18 03:49:17 +0000
commitbdeb1c17efabd7635851d4ab9ae13c729535e9c3 (patch)
tree63e897e8b6436002579aa95f8cbad8b6c113a222
parentInitial commit. (diff)
downloadicinga-php-thirdparty-bdeb1c17efabd7635851d4ab9ae13c729535e9c3.tar.xz
icinga-php-thirdparty-bdeb1c17efabd7635851d4ab9ae13c729535e9c3.zip
Adding upstream version 0.10.0.upstream/0.10.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore3
-rw-r--r--LICENSE21
-rw-r--r--README.md39
-rw-r--r--RELEASE.md11
-rw-r--r--VERSION1
-rwxr-xr-xbin/make-release.sh59
-rw-r--r--composer.json47
-rw-r--r--composer.lock2596
-rw-r--r--vendor/autoload.php7
-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.php290
-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.php449
-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.php203
-rw-r--r--vendor/clue/redis-react/src/LazyClient.php216
-rw-r--r--vendor/clue/redis-react/src/StreamingClient.php180
-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.php554
-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.php447
-rw-r--r--vendor/clue/socks-react/src/Server.php393
-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.php617
-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/composer/ClassLoader.php445
-rw-r--r--vendor/composer/LICENSE21
-rw-r--r--vendor/composer/autoload_classmap.php17
-rw-r--r--vendor/composer/autoload_files.php25
-rw-r--r--vendor/composer/autoload_namespaces.php11
-rw-r--r--vendor/composer/autoload_psr4.php44
-rw-r--r--vendor/composer/autoload_real.php73
-rw-r--r--vendor/composer/autoload_static.php262
-rw-r--r--vendor/composer/installed.json2653
-rw-r--r--vendor/evenement/evenement/LICENSE19
-rw-r--r--vendor/evenement/evenement/composer.json34
-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.php73
-rw-r--r--vendor/guzzlehttp/guzzle/LICENSE19
-rw-r--r--vendor/guzzlehttp/guzzle/composer.json59
-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.php316
-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.php403
-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.php255
-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/LICENSE19
-rw-r--r--vendor/guzzlehttp/promises/composer.json39
-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.php254
-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.php274
-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/LICENSE19
-rw-r--r--vendor/guzzlehttp/psr7/composer.json49
-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.php141
-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.php214
-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/paragonie/random_compat/LICENSE22
-rw-r--r--vendor/paragonie/random_compat/composer.json38
-rw-r--r--vendor/paragonie/random_compat/lib/byte_safe_strings.php195
-rw-r--r--vendor/paragonie/random_compat/lib/cast_to_int.php77
-rw-r--r--vendor/paragonie/random_compat/lib/error_polyfill.php49
-rw-r--r--vendor/paragonie/random_compat/lib/random.php226
-rw-r--r--vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php91
-rw-r--r--vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php190
-rw-r--r--vendor/paragonie/random_compat/lib/random_bytes_libsodium.php91
-rw-r--r--vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php93
-rw-r--r--vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php79
-rw-r--r--vendor/paragonie/random_compat/lib/random_int.php204
-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.php549
-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.php191
-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.php176
-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.php130
-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.php66
-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.php80
-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.php235
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/RedisCluster.php673
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/ReplicationInterface.php52
-rw-r--r--vendor/predis/predis/src/Connection/Aggregate/SentinelReplication.php727
-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.php173
-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.php219
-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.php278
-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.php104
-rw-r--r--vendor/predis/predis/src/Response/Iterator/MultiBulkTuple.php90
-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.php142
-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.json92
-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.php751
-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.php553
-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.php139
-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.php127
-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.php92
-rw-r--r--vendor/react/dns/src/Query/ExecutorInterface.php43
-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.php368
-rw-r--r--vendor/react/dns/src/Query/TimeoutException.php7
-rw-r--r--vendor/react/dns/src/Query/TimeoutExecutor.php30
-rw-r--r--vendor/react/dns/src/Query/UdpTransportExecutor.php213
-rw-r--r--vendor/react/dns/src/RecordNotFoundException.php7
-rw-r--r--vendor/react/dns/src/Resolver/Factory.php123
-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/LICENSE19
-rw-r--r--vendor/react/event-loop/composer.json27
-rw-r--r--vendor/react/event-loop/src/ExtEvLoop.php252
-rw-r--r--vendor/react/event-loop/src/ExtEventLoop.php274
-rw-r--r--vendor/react/event-loop/src/ExtLibevLoop.php199
-rw-r--r--vendor/react/event-loop/src/ExtLibeventLoop.php283
-rw-r--r--vendor/react/event-loop/src/ExtUvLoop.php341
-rw-r--r--vendor/react/event-loop/src/Factory.php44
-rw-r--r--vendor/react/event-loop/src/LoopInterface.php463
-rw-r--r--vendor/react/event-loop/src/SignalsHandler.php63
-rw-r--r--vendor/react/event-loop/src/StreamSelectLoop.php308
-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.php107
-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.json52
-rw-r--r--vendor/react/http/src/Browser.php740
-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/Io/BufferedBody.php176
-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.php329
-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.php278
-rw-r--r--vendor/react/http/src/Io/Sender.php159
-rw-r--r--vendor/react/http/src/Io/StreamingServer.php378
-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.php65
-rw-r--r--vendor/react/http/src/Message/ResponseException.php43
-rw-r--r--vendor/react/http/src/Message/ServerRequest.php194
-rw-r--r--vendor/react/http/src/Middleware/LimitConcurrentRequestsMiddleware.php214
-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.php327
-rw-r--r--vendor/react/promise-stream/LICENSE21
-rw-r--r--vendor/react/promise-stream/composer.json31
-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.php356
-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.json28
-rw-r--r--vendor/react/promise-timer/src/TimeoutException.php22
-rw-r--r--vendor/react/promise-timer/src/functions.php81
-rw-r--r--vendor/react/promise-timer/src/functions_include.php7
-rw-r--r--vendor/react/promise/LICENSE22
-rw-r--r--vendor/react/promise/composer.json29
-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.php351
-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.php139
-rw-r--r--vendor/react/socket/src/ConnectorInterface.php58
-rw-r--r--vendor/react/socket/src/DnsConnector.php115
-rw-r--r--vendor/react/socket/src/FixedUriConnector.php41
-rw-r--r--vendor/react/socket/src/HappyEyeBallsConnectionBuilder.php358
-rw-r--r--vendor/react/socket/src/HappyEyeBallsConnector.php53
-rw-r--r--vendor/react/socket/src/LimitingServer.php203
-rw-r--r--vendor/react/socket/src/SecureConnector.php84
-rw-r--r--vendor/react/socket/src/SecureServer.php199
-rw-r--r--vendor/react/socket/src/Server.php73
-rw-r--r--vendor/react/socket/src/ServerInterface.php151
-rw-r--r--vendor/react/socket/src/StreamEncryption.php141
-rw-r--r--vendor/react/socket/src/TcpConnector.php122
-rw-r--r--vendor/react/socket/src/TcpServer.php236
-rw-r--r--vendor/react/socket/src/TimeoutConnector.php50
-rw-r--r--vendor/react/socket/src/UnixConnector.php44
-rw-r--r--vendor/react/socket/src/UnixServer.php141
-rw-r--r--vendor/react/stream/LICENSE19
-rw-r--r--vendor/react/stream/composer.json25
-rw-r--r--vendor/react/stream/src/CompositeStream.php83
-rw-r--r--vendor/react/stream/src/DuplexResourceStream.php224
-rw-r--r--vendor/react/stream/src/DuplexStreamInterface.php39
-rw-r--r--vendor/react/stream/src/ReadableResourceStream.php177
-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.php165
-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.php227
-rw-r--r--vendor/symfony/polyfill-ctype/LICENSE19
-rw-r--r--vendor/symfony/polyfill-ctype/bootstrap.php46
-rw-r--r--vendor/symfony/polyfill-ctype/composer.json38
-rw-r--r--vendor/symfony/polyfill-intl-idn/Idn.php923
-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.php141
-rw-r--r--vendor/symfony/polyfill-intl-idn/composer.json45
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/LICENSE19
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/Normalizer.php308
-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.php19
-rw-r--r--vendor/symfony/polyfill-intl-normalizer/composer.json39
-rw-r--r--vendor/symfony/polyfill-php70/LICENSE19
-rw-r--r--vendor/symfony/polyfill-php70/Php70.php74
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php5
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php5
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php5
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/Error.php5
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php5
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php23
-rw-r--r--vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php5
-rw-r--r--vendor/symfony/polyfill-php70/bootstrap.php30
-rw-r--r--vendor/symfony/polyfill-php70/composer.json37
-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
755 files changed, 101122 insertions, 0 deletions
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/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..5c84e5d
--- /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 (>= 5.6, 7+ recommended)
+
+## 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/1.0.0` or a tag like `v1.0.0` is fine.
+
+### Examples
+
+**Sample Tarball installation**
+
+```sh
+INSTALL_PATH="/usr/share/icinga-php/vendor"
+INSTALL_VERSION="v1.0.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/1.0.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..c28863e
--- /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_web56 bin/make-release.sh 1.0.0 --no-tag
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..bf057db
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+v0.10.0
diff --git a/bin/make-release.sh b/bin/make-release.sh
new file mode 100755
index 0000000..dc63fe1
--- /dev/null
+++ b/bin/make-release.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+VERSION="$1"
+NO_TAG="$2"
+
+if [[ -z $VERSION ]]; then
+ echo "USAGE: $0 <version>"
+ 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
+
+BRANCH="stable/$VERSION"
+git checkout -b "$BRANCH" || fail "Version branch $BRANCH already exists"
+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
+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 [ "$NO_TAG" != "--no-tag" ]; 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/composer.json b/composer.json
new file mode 100644
index 0000000..b8394ef
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,47 @@
+{
+ "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": "5.6.3"
+ }
+ },
+ "support": {
+ "issues": "https://github.com/Icinga/icinga-php-thirdparty/issues"
+ },
+ "require": {
+ "php": ">=5.6.3",
+ "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",
+ "evenement/evenement": "^2",
+ "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"
+ },
+ "require-dev": {
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..9e7b450
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,2596 @@
+{
+ "_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": "848b7d6e7217c8fb68de92edf50f1ac0",
+ "packages": [
+ {
+ "name": "clue/block-react",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-block.git",
+ "reference": "c8e7583ae55127b89d6915480ce295bac81c4f88"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-block/zipball/c8e7583ae55127b89d6915480ce295bac81c4f88",
+ "reference": "c8e7583ae55127b89d6915480ce295bac81c4f88",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/http": "^1.0"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-08-21T14:09:44+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"
+ ],
+ "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"
+ ],
+ "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.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-http-proxy.git",
+ "reference": "005e7d518a1e69fc8d321e3f719c9024d4d4200d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/005e7d518a1e69fc8d321e3f719c9024d4d4200d",
+ "reference": "005e7d518a1e69fc8d321e3f719c9024d4d4200d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": " ^2.1 || ^1.2.1",
+ "react/socket": "^1.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/http": "^1.0"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-23T12:32:10+00:00"
+ },
+ {
+ "name": "clue/mq-react",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-mq.git",
+ "reference": "490556d66c804300604d1b4d5e42fc027e14f1eb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-mq/zipball/490556d66c804300604d1b4d5e42fc027e14f1eb",
+ "reference": "490556d66c804300604d1b4d5e42fc027e14f1eb",
+ "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.0 || ^0.5",
+ "react/http": "^1.0"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-16T10:42:49+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"
+ ],
+ "time": "2017-06-06T16:07:10+00:00"
+ },
+ {
+ "name": "clue/redis-react",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-redis.git",
+ "reference": "a3630f14cc0852d9b0d4bf8f5732479389215792"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/a3630f14cc0852d9b0d4bf8f5732479389215792",
+ "reference": "a3630f14cc0852d9b0d4bf8f5732479389215792",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-protocol": "0.3.*",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/promise": "^2.0 || ^1.1",
+ "react/promise-timer": "^1.5",
+ "react/socket": "^1.1"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-25T11:10:39+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"
+ ],
+ "time": "2018-11-07T17:19:24+00:00"
+ },
+ {
+ "name": "clue/socket-raw",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/php-socket-raw.git",
+ "reference": "089ffa05fa75bdc4e919aac44bbc435b3ef640ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/php-socket-raw/zipball/089ffa05fa75bdc4e919aac44bbc435b3ef640ef",
+ "reference": "089ffa05fa75bdc4e919aac44bbc435b3ef640ef",
+ "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/php-socket-raw",
+ "keywords": [
+ "Socket",
+ "client",
+ "datagram",
+ "dgram",
+ "icmp",
+ "ipv6",
+ "server",
+ "stream",
+ "tcp",
+ "udg",
+ "udp",
+ "unix"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-27T13:16:18+00:00"
+ },
+ {
+ "name": "clue/socks-react",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-socks.git",
+ "reference": "d2d87448e8990ab18f5c72cda0195cf1c506baf8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-socks/zipball/d2d87448e8990ab18f5c72cda0195cf1c506baf8",
+ "reference": "d2d87448e8990ab18f5c72cda0195cf1c506baf8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/socket": "^1.1"
+ },
+ "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.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/http": "^1.0"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-23T12:35:01+00:00"
+ },
+ {
+ "name": "clue/stdio-react",
+ "version": "v2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-stdio.git",
+ "reference": "5722686d3cc0cdf2ccedb6079bfd066220611f00"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-stdio/zipball/5722686d3cc0cdf2ccedb6079bfd066220611f00",
+ "reference": "5722686d3cc0cdf2ccedb6079bfd066220611f00",
+ "shasum": ""
+ },
+ "require": {
+ "clue/term-react": "^1.0 || ^0.1.1",
+ "clue/utf8-react": "^1.0 || ^0.1",
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-20T14:28:39+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"
+ ],
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-11-06T11:48:09+00:00"
+ },
+ {
+ "name": "evenement/evenement",
+ "version": "v2.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/6ba9a777870ab49f417e703229d53931ed40fd7a",
+ "reference": "6ba9a777870ab49f417e703229d53931ed40fd7a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0||^5.7||^4.8.35"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "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"
+ ],
+ "time": "2017-07-17T17:39:19+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.5.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
+ "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
+ "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": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "time": "2020-06-16T21:01:06+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
+ "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "time": "2021-03-07T09:25:29+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.8.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "dc960a912984efb74d0a90222870c72c87f10c91"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
+ "reference": "dc960a912984efb74d0a90222870c72c87f10c91",
+ "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": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "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"
+ ],
+ "time": "2021-04-26T09:17:50+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v2.0.20",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a",
+ "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/random.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "time": "2021-04-17T09:33:01+00:00"
+ },
+ {
+ "name": "predis/predis",
+ "version": "v1.1.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/predis/predis.git",
+ "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/predis/predis/zipball/b240daa106d4e02f0c5b7079b41e31ddf66fddf8",
+ "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8",
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/tillkruss",
+ "type": "github"
+ }
+ ],
+ "time": "2021-04-04T19:34:46+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"
+ ],
+ "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.",
+ "time": "2019-03-08T08:55:37+00:00"
+ },
+ {
+ "name": "ramsey/uuid",
+ "version": "3.9.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/uuid.git",
+ "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92",
+ "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "paragonie/random_compat": "^1 | ^2 | 9.99.99",
+ "php": "^5.4 | ^7 | ^8",
+ "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",
+ "jakub-onderka/php-parallel-lint": "^1",
+ "mockery/mockery": "^0.9.11 | ^1",
+ "moontoast/math": "^1.1",
+ "paragonie/random-lib": "^2",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1",
+ "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "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": {
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ },
+ "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"
+ ],
+ "time": "2020-02-21T04:36:14+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"
+ ],
+ "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.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/child-process.git",
+ "reference": "70486012c0265264d2afa489ff32e7cdb76000d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/child-process/zipball/70486012c0265264d2afa489ff32e7cdb76000d9",
+ "reference": "70486012c0265264d2afa489ff32e7cdb76000d9",
+ "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.5",
+ "react/stream": "^1.0 || ^0.7.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/socket": "^1.0",
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-02-05T13:08:00+00:00"
+ },
+ {
+ "name": "react/datagram",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/datagram.git",
+ "reference": "4f4111503aaafc4104de047a1ac5bf79ee0bbaa3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/datagram/zipball/4f4111503aaafc4104de047a1ac5bf79ee0bbaa3",
+ "reference": "4f4111503aaafc4104de047a1ac5bf79ee0bbaa3",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/dns": "^1.1",
+ "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": "^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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-02-12T12:12:01+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "bf76d1c312c0c280c4ce53119cd7d08db23ffb4c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/bf76d1c312c0c280c4ce53119cd7d08db23ffb4c",
+ "reference": "bf76d1c312c0c280c4ce53119cd7d08db23ffb4c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.2"
+ },
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-06-21T11:56:09+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "6d24de090cd59cfc830263cfba965be77b563c13"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/6d24de090cd59cfc830263cfba965be77b563c13",
+ "reference": "6d24de090cd59cfc830263cfba965be77b563c13",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 || ^6.4 || ^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"
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "time": "2020-01-01T18:39:52+00:00"
+ },
+ {
+ "name": "react/http",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/http.git",
+ "reference": "bc537273d11ee769c723a830e63aa33c0c35a530"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/http/zipball/bc537273d11ee769c723a830e63aa33c0c35a530",
+ "reference": "bc537273d11ee769c723a830e63aa33c0c35a530",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "psr/http-message": "^1.0",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/promise": "^2.3 || ^1.2.1",
+ "react/promise-stream": "^1.1",
+ "react/socket": "^1.6",
+ "react/stream": "^1.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.1",
+ "clue/http-proxy-react": "^1.3",
+ "clue/reactphp-ssh-proxy": "^1.0",
+ "clue/socks-react": "^1.0",
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2021-04-11T18:07:28+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"
+ ],
+ "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.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4",
+ "reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "time": "2020-05-12T15:16:56+00:00"
+ },
+ {
+ "name": "react/promise-stream",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-stream.git",
+ "reference": "6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe",
+ "reference": "6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe",
+ "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": "^7.0 || ^6.4 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/promise-timer": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Promise\\Stream\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "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"
+ ],
+ "time": "2019-07-03T12:29:10+00:00"
+ },
+ {
+ "name": "react/promise-timer",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-timer.git",
+ "reference": "daee9baf6ef30c43ea4c86399f828bb5f558f6e6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/daee9baf6ef30c43ea4c86399f828bb5f558f6e6",
+ "reference": "daee9baf6ef30c43ea4c86399f828bb5f558f6e6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Promise\\Timer\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "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"
+ ],
+ "time": "2020-07-10T12:18:06+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
+ "reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.1",
+ "react/event-loop": "^1.0 || ^0.5",
+ "react/promise": "^2.6.0 || ^1.2.1",
+ "react/promise-timer": "^1.4.0",
+ "react/stream": "^1.1"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.2",
+ "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"
+ ],
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2020-08-28T12:49:05+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/7c02b510ee3f582c810aeccd3a197b9c2f52ff1a",
+ "reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "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"
+ ],
+ "time": "2020-05-04T10:17:57+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": {
+ "psr-4": {
+ "RingCentral\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "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"
+ ],
+ "time": "2018-05-29T20:21:04+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.19.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
+ "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.19-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "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"
+ ],
+ "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": "2020-10-23T09:01:57+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-idn",
+ "version": "v1.19.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-idn.git",
+ "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/4ad5115c0f5d5172a9fe8147675ec6de266d8826",
+ "reference": "4ad5115c0f5d5172a9fe8147675ec6de266d8826",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/polyfill-intl-normalizer": "^1.10",
+ "symfony/polyfill-php70": "^1.10",
+ "symfony/polyfill-php72": "^1.10"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.19-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Idn\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "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"
+ ],
+ "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": "2020-10-21T09:57:48+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.19.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8db0ae7936b42feb370840cf24de1a144fb0ef27",
+ "reference": "8db0ae7936b42feb370840cf24de1a144fb0ef27",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.19-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "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"
+ ],
+ "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": "2020-10-23T09:01:57+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php70",
+ "version": "v1.19.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php70.git",
+ "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/3fe414077251a81a1b15b1c709faf5c2fbae3d4e",
+ "reference": "3fe414077251a81a1b15b1c709faf5c2fbae3d4e",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/random_compat": "~1.0|~2.0|~9.99",
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.19-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php70\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "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 backporting some PHP 7.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "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": "2020-10-23T09:01:57+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php72",
+ "version": "v1.19.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php72.git",
+ "reference": "beecef6b463b06954638f02378f52496cb84bacc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/beecef6b463b06954638f02378f52496cb84bacc",
+ "reference": "beecef6b463b06954638f02378f52496cb84bacc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.19-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php72\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "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": "2020-10-23T09:01:57+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.6.3",
+ "ext-curl": "*"
+ },
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "5.6.3"
+ },
+ "plugin-api-version": "1.1.0"
+}
diff --git a/vendor/autoload.php b/vendor/autoload.php
new file mode 100644
index 0000000..484a58d
--- /dev/null
+++ b/vendor/autoload.php
@@ -0,0 +1,7 @@
+<?php
+
+// autoload.php @generated by Composer
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInita1310fbd7327cd7832926f64cddb365b::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..4545462
--- /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.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.7 || ^1.2.1",
+ "react/promise-timer": "^1.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/http": "^1.0"
+ }
+}
diff --git a/vendor/clue/block-react/src/functions.php b/vendor/clue/block-react/src/functions.php
new file mode 100644
index 0000000..0fda798
--- /dev/null
+++ b/vendor/clue/block-react/src/functions.php
@@ -0,0 +1,290 @@
+<?php
+
+namespace Clue\React\Block;
+
+use React\EventLoop\LoopInterface;
+use React\Promise\PromiseInterface;
+use React\Promise\CancellablePromiseInterface;
+use UnderflowException;
+use Exception;
+use React\Promise;
+use React\Promise\Timer;
+use React\Promise\Timer\TimeoutException;
+
+/**
+ * Wait/sleep for `$time` seconds.
+ *
+ * ```php
+ * 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.
+ *
+ * @param float $time
+ * @param LoopInterface $loop
+ * @return void
+ */
+function sleep($time, LoopInterface $loop)
+{
+ await(Timer\resolve($time, $loop), $loop);
+}
+
+/**
+ * Block waiting for the given `$promise` to be fulfilled.
+ *
+ * ```php
+ * $result = Block\await($promise, $loop, $timeout);
+ * ```
+ *
+ * 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 = 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/).
+ *
+ * If no `$timeout` argument is given and the promise stays pending, then this
+ * will potentially wait/block forever until the promise is settled.
+ *
+ * If a `$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.
+ *
+ * @param PromiseInterface $promise
+ * @param LoopInterface $loop
+ * @param null|float $timeout (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, $timeout = null)
+{
+ $wait = true;
+ $resolved = null;
+ $exception = null;
+ $rejected = false;
+
+ 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 = new \UnexpectedValueException(
+ 'Promise rejected with unexpected value of type ' . (is_object($exception) ? get_class($exception) : gettype($exception)),
+ 0,
+ $exception instanceof \Throwable ? $exception : null
+ );
+ }
+
+ throw $exception;
+ }
+
+ return $resolved;
+}
+
+/**
+ * Wait for ANY of the given promises to be fulfilled.
+ *
+ * ```php
+ * $promises = array(
+ * $promise1,
+ * $promise2
+ * );
+ *
+ * $firstResult = Block\awaitAny($promises, $loop, $timeout);
+ *
+ * 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.
+ *
+ * If no `$timeout` argument is given and ALL promises stay pending, then this
+ * will potentially wait/block forever until the promise is fulfilled.
+ *
+ * If a `$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.
+ *
+ * @param array $promises
+ * @param LoopInterface $loop
+ * @param null|float $timeout (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, $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 = Block\awaitAll($promises, $loop, $timeout);
+ *
+ * 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.
+ *
+ * If no `$timeout` argument is given and ANY promises stay pending, then this
+ * will potentially wait/block forever until the promise is fulfilled.
+ *
+ * If a `$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.
+ *
+ * @param array $promises
+ * @param LoopInterface $loop
+ * @param null|float $timeout (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, $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 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..e34a14c
--- /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"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "Clue\\React\\HttpProxy\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\HttpProxy\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": " ^2.1 || ^1.2.1",
+ "react/socket": "^1.1",
+ "ringcentral/psr7": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/http": "^1.0",
+ "clue/block-react": "^1.1"
+ }
+}
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..020e12a
--- /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\ConnectorInterface;
+use React\Socket\FixedUriConnector;
+
+/**
+ * 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 In its most simple form, the given
+ * connector will be a \React\Socket\Connector if you want to connect to
+ * a given IP address.
+ * @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, 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
+ );
+ }
+
+ 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;
+ $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..654945a
--- /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.0 || ^0.5",
+ "react/http": "^1.0"
+ }
+}
diff --git a/vendor/clue/mq-react/src/Queue.php b/vendor/clue/mq-react/src/Queue.php
new file mode 100644
index 0000000..cefdf34
--- /dev/null
+++ b/vendor/clue/mq-react/src/Queue.php
@@ -0,0 +1,449 @@
+<?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
+ * $loop = React\EventLoop\Factory::create();
+ * $browser = new React\Http\Browser($loop);
+ *
+ * $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
+ * $loop = React\EventLoop\Factory::create();
+ * $browser = new React\Http\Browser($loop);
+ *
+ * $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();
+ }
+
+ 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..3a12889
--- /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.0 || ^0.5",
+ "react/promise": "^2.0 || ^1.1",
+ "react/promise-timer": "^1.5",
+ "react/socket": "^1.1"
+ },
+ "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..1b514df
--- /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 resolved 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..ce95c41
--- /dev/null
+++ b/vendor/clue/redis-react/src/Factory.php
@@ -0,0 +1,203 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Clue\Redis\Protocol\Factory as ProtocolFactory;
+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;
+use InvalidArgumentException;
+
+class Factory
+{
+ private $loop;
+ private $connector;
+ private $protocol;
+
+ /**
+ * @param LoopInterface $loop
+ * @param ConnectorInterface|null $connector [optional] Connector to use.
+ * Should be `null` in order to use default Connector.
+ * @param ProtocolFactory|null $protocol
+ */
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null, ProtocolFactory $protocol = null)
+ {
+ if ($connector === null) {
+ $connector = new Connector($loop);
+ }
+
+ if ($protocol === null) {
+ $protocol = new ProtocolFactory();
+ }
+
+ $this->loop = $loop;
+ $this->connector = $connector;
+ $this->protocol = $protocol;
+ }
+
+ /**
+ * Create Redis client connected to address of given redis instance
+ *
+ * @param string $target Redis server URI to connect to
+ * @return \React\Promise\PromiseInterface<Client> resolves with Client or rejects with \Exception
+ */
+ public function createClient($target)
+ {
+ try {
+ $parts = $this->parseUrl($target);
+ } catch (InvalidArgumentException $e) {
+ return \React\Promise\reject($e);
+ }
+
+ $connecting = $this->connector->connect($parts['authority']);
+ $deferred = new Deferred(function ($_, $reject) use ($connecting) {
+ // connection cancelled, start with rejecting attempt, then clean up
+ $reject(new \RuntimeException('Connection to Redis server cancelled'));
+
+ // 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) {
+ throw new \RuntimeException(
+ 'Connection to Redis server failed because underlying transport connection failed',
+ 0,
+ $e
+ );
+ });
+
+ if (isset($parts['auth'])) {
+ $promise = $promise->then(function (StreamingClient $client) use ($parts) {
+ return $client->auth($parts['auth'])->then(
+ function () use ($client) {
+ return $client;
+ },
+ function ($error) use ($client) {
+ $client->close();
+
+ throw new \RuntimeException(
+ 'Connection to Redis server failed because AUTH command failed',
+ 0,
+ $error
+ );
+ }
+ );
+ });
+ }
+
+ if (isset($parts['db'])) {
+ $promise = $promise->then(function (StreamingClient $client) use ($parts) {
+ return $client->select($parts['db'])->then(
+ function () use ($client) {
+ return $client;
+ },
+ function ($error) use ($client) {
+ $client->close();
+
+ throw new \RuntimeException(
+ 'Connection to Redis server failed because SELECT command failed',
+ 0,
+ $error
+ );
+ }
+ );
+ });
+ }
+
+ $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($parts['timeout']) ? $parts['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) {
+ if ($e instanceof TimeoutException) {
+ throw new \RuntimeException(
+ 'Connection to Redis server timed out after ' . $e->getTimeout() . ' seconds'
+ );
+ }
+ 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);
+ }
+
+ /**
+ * @param string $target
+ * @return array with keys authority, auth and db
+ * @throws InvalidArgumentException
+ */
+ private function parseUrl($target)
+ {
+ $ret = array();
+ // support `redis+unix://` scheme for Unix domain socket (UDS) paths
+ if (preg_match('/^redis\+unix:\/\/([^:]*:[^@]*@)?(.+?)(\?.*)?$/', $target, $match)) {
+ $ret['authority'] = 'unix://' . $match[2];
+ $target = 'redis://' . (isset($match[1]) ? $match[1] : '') . 'localhost' . (isset($match[3]) ? $match[3] : '');
+ }
+
+ if (strpos($target, '://') === false) {
+ $target = 'redis://' . $target;
+ }
+
+ $parts = parse_url($target);
+ if ($parts === false || !isset($parts['scheme'], $parts['host']) || !in_array($parts['scheme'], array('redis', 'rediss'))) {
+ throw new InvalidArgumentException('Given URL can not be parsed');
+ }
+
+ if (isset($parts['pass'])) {
+ $ret['auth'] = rawurldecode($parts['pass']);
+ }
+
+ if (isset($parts['path']) && $parts['path'] !== '') {
+ // skip first slash
+ $ret['db'] = substr($parts['path'], 1);
+ }
+
+ if (!isset($ret['authority'])) {
+ $ret['authority'] =
+ ($parts['scheme'] === 'rediss' ? 'tls://' : '') .
+ $parts['host'] . ':' .
+ (isset($parts['port']) ? $parts['port'] : 6379);
+ }
+
+ if (isset($parts['query'])) {
+ $args = array();
+ parse_str($parts['query'], $args);
+
+ if (isset($args['password'])) {
+ $ret['auth'] = $args['password'];
+ }
+
+ if (isset($args['db'])) {
+ $ret['db'] = $args['db'];
+ }
+
+ if (isset($args['timeout'])) {
+ $ret['timeout'] = (float) $args['timeout'];
+ }
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-react/src/LazyClient.php b/vendor/clue/redis-react/src/LazyClient.php
new file mode 100644
index 0000000..bfb2fef
--- /dev/null
+++ b/vendor/clue/redis-react/src/LazyClient.php
@@ -0,0 +1,216 @@
+<?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(\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 $client) use ($self, &$pending, &$idleTimer, &$subscribed, &$psubscribed, $loop) {
+ // connection completed => remember only until closed
+ $client->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
+ $client->on('subscribe', function ($channel) use (&$subscribed) {
+ $subscribed[$channel] = true;
+ });
+ $client->on('psubscribe', function ($pattern) use (&$psubscribed) {
+ $psubscribed[$pattern] = true;
+ });
+ $client->on('unsubscribe', function ($channel) use (&$subscribed) {
+ unset($subscribed[$channel]);
+ });
+ $client->on('punsubscribe', function ($pattern) use (&$psubscribed) {
+ unset($psubscribed[$pattern]);
+ });
+
+ Util::forwardEvents(
+ $client,
+ $self,
+ array(
+ 'message',
+ 'subscribe',
+ 'unsubscribe',
+ 'pmessage',
+ 'psubscribe',
+ 'punsubscribe',
+ )
+ );
+
+ return $client;
+ }, 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'));
+ }
+
+ $that = $this;
+ return $this->client()->then(function (Client $client) use ($name, $args, $that) {
+ $that->awake();
+ return \call_user_func_array(array($client, $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 $client) use ($that) {
+ $client->on('close', function () use ($that) {
+ $that->close();
+ });
+ $client->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 $client) {
+ $client->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 $client) {
+ $client->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..0d5f9bb
--- /dev/null
+++ b/vendor/clue/redis-react/src/StreamingClient.php
@@ -0,0 +1,180 @@
+<?php
+
+namespace Clue\React\Redis;
+
+use Evenement\EventEmitter;
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Parser\ParserException;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Clue\Redis\Protocol\Factory as ProtocolFactory;
+use UnderflowException;
+use RuntimeException;
+use InvalidArgumentException;
+use React\Promise\Deferred;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+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($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 closed'));
+ } elseif (count($args) !== 1 && in_array($name, $pubsubs)) {
+ $request->reject(new InvalidArgumentException('PubSub commands limited to single argument'));
+ } elseif ($name === 'monitor') {
+ $request->reject(new \BadMethodCallException('MONITOR command explicitly not supported'));
+ } 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');
+ }
+
+ $request = array_shift($this->requests);
+ /* @var $request 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;
+
+ $this->stream->close();
+
+ $this->emit('close');
+
+ // reject all remaining requests in the queue
+ while($this->requests) {
+ $request = array_shift($this->requests);
+ /* @var $request Request */
+ $request->reject(new RuntimeException('Connection closing'));
+ }
+ }
+}
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..30ac295
--- /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/php-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..bd72176
--- /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 $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..4b64fec
--- /dev/null
+++ b/vendor/clue/socket-raw/src/Socket.php
@@ -0,0 +1,554 @@
+<?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
+ if ($this->selectWrite($timeout) === false) {
+ 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 ? null : (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 ? null : (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..38af58b
--- /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"
+ }
+ ],
+ "autoload": {
+ "psr-4": {"Clue\\React\\Socks\\": "src/"}
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Socks\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/promise": "^2.1 || ^1.2",
+ "react/socket": "^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/http": "^1.0",
+ "clue/connection-manager-extra": "^1.0 || ^0.7",
+ "clue/block-react": "^1.1"
+ }
+}
diff --git a/vendor/clue/socks-react/src/Client.php b/vendor/clue/socks-react/src/Client.php
new file mode 100644
index 0000000..a317f18
--- /dev/null
+++ b/vendor/clue/socks-react/src/Client.php
@@ -0,0 +1,447 @@
+<?php
+
+namespace Clue\React\Socks;
+
+use React\Promise;
+use React\Promise\PromiseInterface;
+use React\Promise\Deferred;
+use React\Socket\ConnectionInterface;
+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;
+
+ public function __construct($socksUri, ConnectorInterface $connector)
+ {
+ // 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
+ );
+ }
+
+ // 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;
+ }
+
+ 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..0db0bca
--- /dev/null
+++ b/vendor/clue/socks-react/src/Server.php
@@ -0,0 +1,393 @@
+<?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\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;
+
+ private $loop;
+
+ private $connector;
+
+ /**
+ * @var null|callable
+ */
+ private $auth;
+
+ /**
+ * @param LoopInterface $loop
+ * @param null|ConnectorInterface $connector
+ * @param null|array|callable $auth
+ */
+ public function __construct(LoopInterface $loop, ConnectorInterface $connector = null, $auth = null)
+ {
+ if ($connector === null) {
+ $connector = new Connector($loop);
+ }
+
+ 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;
+ $this->connector = $connector;
+ }
+
+ /**
+ * @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..09eb64b
--- /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.0 || ^0.5 || ^0.4 || ^0.3",
+ "react/stream": "^1.0 || ^0.7 || ^0.6"
+ },
+ "suggest": {
+ "ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
+ },
+ "autoload": {
+ "psr-4": { "Clue\\React\\Stdio\\": "src/" }
+ },
+ "autoload-dev": {
+ "psr-4": { "Clue\\Tests\\React\\Stdio\\": "tests/" }
+ },
+ "require-dev": {
+ "clue/arguments": "^2.0",
+ "clue/commander": "^1.2",
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+ },
+ "config": {
+ "sort-packages": true
+ }
+}
diff --git a/vendor/clue/stdio-react/src/Readline.php b/vendor/clue/stdio-react/src/Readline.php
new file mode 100644
index 0000000..3f294e5
--- /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 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